p80211netdev.c

来自「Linux的无线局域网方案是一个Linux设备驱动程序和子系统 一揽子方案的用」· C语言 代码 · 共 1,046 行 · 第 1/2 页

C
1,046
字号
         arg = P80211ENUM_truth_false;        if (doPromisc)                arg = P80211ENUM_truth_true;          memcpy(&mibitem.data, &arg, sizeof(UINT32));        memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));        result = p80211req_dorequest(wlandev, (UINT8*)&msg);	/* TODO:  Check result */		DBFEXIT;}/*----------------------------------------------------------------* p80211knetdev_do_ioctl** Handle an ioctl call on one of our devices.  Everything Linux* ioctl specific is done here.  Then we pass the contents of the* ifr->data to the request message handler.** Arguments:*	dev	Linux kernel netdevice*	ifr	Our private ioctl request structure, typed for the*		generic struct ifreq so we can use ptr to func*		w/o cast.** Returns: *	zero on success, a negative errno on failure.  Possible values:*		-ENETDOWN Device isn't up.*		-EBUSY	cmd already in progress*		-ETIME	p80211 cmd timed out (MSD may have its own timers)*		-EFAULT memory fault copying msg from user buffer*		-ENOMEM unable to allocate kernel msg buffer*		-ENOSYS	bad magic, it the cmd really for us?*		-EINTR	sleeping on cmd, awakened by signal, cmd cancelled.** Call Context:*	Process thread (ioctl caller).  TODO: SMP support may require*	locks.----------------------------------------------------------------*/int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd){	int			result = 0;	p80211ioctl_req_t	*req = (p80211ioctl_req_t*)ifr;	wlandevice_t		*wlandev = (wlandevice_t*)dev->priv;	UINT8			*msgbuf;	DBFENTER;	WLAN_LOG_DEBUG2(2, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len);/* compatibility to wireless extensions */#if defined(__LINUX_WLAN__) && defined (__KERNEL__)#if WIRELESS_EXT > 10	/* to be or not to be a wireless extension- compatible ioctl */	if(p80211wext_check_ioctl(cmd)) {	  if((result = p80211wext_support_ioctl(dev, ifr, cmd)) 	     != (-EOPNOTSUPP)) {	    return result;	  }	}#endif#endif	/* Test the magic, assume ifr is good if it's there */	if ( req->magic != P80211_IOCTL_MAGIC ) {		result = -ENOSYS;		goto bail;	}	if ( cmd == P80211_IFTEST ) {		result = 0;		goto bail;	} else if ( cmd != P80211_IFREQ ) {		result = -ENOSYS;		goto bail;	}	/* Allocate a buf of size req->len */	if ((msgbuf = kmalloc( req->len, GFP_KERNEL))) {		if ( copy_from_user( msgbuf, req->data, req->len) ) {			result = -EFAULT;		} else {			result = p80211req_dorequest( wlandev, msgbuf);		}		if ( result == 0 ) {			if ( copy_to_user( req->data, msgbuf, req->len)) {				result = -EFAULT;			}		}		kfree(msgbuf);	} else {		result = -ENOMEM;	}bail:	DBFEXIT;	return result; /* If allocate,copyfrom or copyto fails, return errno */}/*----------------------------------------------------------------* p80211knetdev_set_mac_address** Handles the ioctl for changing the MACAddress of a netdevice* * references: linux/netdevice.h and drivers/net/net_init.c** NOTE: [MSM] We only prevent address changes when the netdev is* up.  We don't control anything based on dot11 state.  If the * address is changed on a STA that's currently associated, you* will probably lose the ability to send and receive data frames.* Just be aware.  Therefore, this should usually only be done* prior to scan/join/auth/assoc.** Arguments:*	dev	netdevice struct*	addr	the new MACAddress (a struct)** Returns:*	zero on success, a negative errno on failure.  Possible values:*		-EBUSY	device is bussy (cmd not possible)*		-and errors returned by: p80211req_dorequest(..)** by: Collin R. Mulliner <collin@mulliner.org>----------------------------------------------------------------*/int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr){	struct sockaddr			*new_addr = addr;	p80211msg_dot11req_mibset_t	dot11req;	p80211item_unk392_t		*mibattr;	p80211item_pstr6_t		*macaddr;	p80211item_uint32_t		*resultcode;	int result = 0;		DBFENTER;	/* If we're running, we don't allow MAC address changes */#if (LINUX_VERSION_CODE < WLAN_KVERSION(2,3,38) )	if ( dev->start) {		return -EBUSY;	}#else	if (netif_running(dev)) {		return -EBUSY;	}#endif	/* Set up some convenience pointers. */	mibattr = &dot11req.mibattribute;	macaddr = (p80211item_pstr6_t*)&mibattr->data;	resultcode = &dot11req.resultcode;	/* Set up a dot11req_mibset */	memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t));	dot11req.msgcode = DIDmsg_dot11req_mibset;	dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t);	memcpy(dot11req.devname, 		((wlandevice_t*)(dev->priv))->name, 		WLAN_DEVNAMELEN_MAX - 1);	/* Set up the mibattribute argument */	mibattr->did = DIDmsg_dot11req_mibset_mibattribute;	mibattr->status = P80211ENUM_msgitem_status_data_ok;	mibattr->len = sizeof(mibattr->data);		macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress;	macaddr->status = P80211ENUM_msgitem_status_data_ok;	macaddr->len = sizeof(macaddr->data);	macaddr->data.len = WLAN_ADDR_LEN;	memcpy(&macaddr->data.data, new_addr->sa_data, WLAN_ADDR_LEN);	/* Set up the resultcode argument */	resultcode->did = DIDmsg_dot11req_mibset_resultcode;	resultcode->status = P80211ENUM_msgitem_status_no_value;	resultcode->len = sizeof(resultcode->data);	resultcode->data = 0;		/* now fire the request */	result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req);	/* If the request wasn't successful, report an error and don't	 * change the netdev address	 */	if ( result != 0 || resultcode->data != P80211ENUM_resultcode_success) {		WLAN_LOG_ERROR0(		"Low-level driver failed dot11req_mibset(dot11MACAddress).\n");		result = -EADDRNOTAVAIL;	} else {		/* everything's ok, change the addr in netdev */		memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len);	}	DBFEXIT;	return result;}/*----------------------------------------------------------------* wlan_setup** Roughly matches the functionality of ether_setup.  Here* we set up any members of the wlandevice structure that are common* to all devices.  Additionally, we allocate a linux 'struct device'* and perform the same setup as ether_setup.** Note: It's important that the caller have setup the wlandev->name*	ptr prior to calling this function.** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	zero on success, non-zero otherwise.* Call Context:*	Should be process thread.  We'll assume it might be*	interrupt though.  When we add support for statically*	compiled drivers, this function will be called in the *	context of the kernel startup code.----------------------------------------------------------------*/int wlan_setup(wlandevice_t *wlandev){	int		result = 0;	netdevice_t	*dev;	DBFENTER;	if (wlandev->name == NULL ) {		WLAN_LOG_ERROR0("called without wlandev->name set.\n");		result = 1;	} else {		/* Set up the wlandev */		wlandev->state = WLAN_DEVICE_CLOSED;		wlandev->ethconv = WLAN_ETHCONV_RFC1042;		wlandev->macmode = WLAN_MACMODE_NONE;		init_waitqueue_head(&wlandev->reqwq);		/* Allocate and initialize the struct device */		dev = kmalloc(sizeof(netdevice_t), GFP_ATOMIC);		if ( dev == NULL ) {			WLAN_LOG_ERROR0("Failed to alloc netdev.\n");			result = 1;		} else {			memset( dev, 0, sizeof(netdevice_t));			wlandev->netdev = dev;			dev->priv = wlandev;			dev->hard_start_xmit =	&p80211knetdev_hard_start_xmit;			dev->get_stats =	&p80211knetdev_get_stats;			dev->do_ioctl = 	&p80211knetdev_do_ioctl;			dev->set_multicast_list = &p80211knetdev_set_multicast_list;			dev->init =		&p80211knetdev_init;			dev->open =		&p80211knetdev_open;			dev->stop =		&p80211knetdev_stop;#if defined(__LINUX_WLAN__) && defined (__KERNEL__)#if WIRELESS_EXT > 10			/* called by /proc/net/wireless */			dev->get_wireless_stats = &p80211wext_get_wireless_stats;#endif#endif			#if (LINUX_VERSION_CODE < WLAN_KVERSION(2,3,38) )			dev->tbusy = 1;#endif#if (LINUX_VERSION_CODE < WLAN_KVERSION(2,3,99) )			dev->name = wlandev->name;#endif			ether_setup(dev);						/*			 * set new function to handle the ioctl for			 * changing the mac address			 *			 * must be after "ether_setup()" because			 * "ether_setup()" sets the pointer to the			 * default function but we need to do more			 *			 * see p80211knetdev_set_mac_address(...)			 * above			 *			 * by: Collin R. Mulliner			 * <collin@mulliner.org>			 */			dev->set_mac_address =	&p80211knetdev_set_mac_address;		}	}	DBFEXIT;	return result;}/*----------------------------------------------------------------* wlan_unsetup** This function is paired with the wlan_setup routine.  It should* be called after unregister_wlandev.  Basically, all it does is* free the 'struct device' that's associated with the wlandev.* We do it here because the 'struct device' isn't allocated * explicitly in the driver code, it's done in wlan_setup.  To* do the free in the driver might seem like 'magic'.** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	zero on success, non-zero otherwise.* Call Context:*	Should be process thread.  We'll assume it might be*	interrupt though.  When we add support for statically*	compiled drivers, this function will be called in the *	context of the kernel startup code.----------------------------------------------------------------*/int wlan_unsetup(wlandevice_t *wlandev){	int		result = 0;	DBFENTER;	if (wlandev->netdev == NULL ) {		WLAN_LOG_ERROR0("called without wlandev->netdev set.\n");		result = 1;	} else {		kfree_s(wlandev->netdev, sizeof(netdevice_t));		wlandev->netdev = NULL;	}	DBFEXIT;	return 0;}/*----------------------------------------------------------------* register_wlandev** Roughly matches the functionality of register_netdev.  This function* is called after the driver has successfully probed and set up the* resources for the device.  It's now ready to become a named device* in the Linux system.** First we allocate a name for the device (if not already set), then* we call the Linux function register_netdevice.** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	zero on success, non-zero otherwise.* Call Context:*	Can be either interrupt or not.----------------------------------------------------------------*/int register_wlandev(wlandevice_t *wlandev){	int		i = -1;	netdevice_t	*dev = wlandev->netdev;	DBFENTER;	rtnl_lock();	if ( wlandev->name != NULL && 		(wlandev->name[0] == '\0' || wlandev->name[0] == ' ') ) {		i = wlandev_get_index(wlandev);	}#if ( LINUX_VERSION_CODE >= WLAN_KVERSION(2,3,99) )	strcpy(dev->name, wlandev->name);#endif	if (register_netdevice(dev)) {		if ( i >= 0 ) {			wlandev_clear_index(wlandev);		}		rtnl_unlock();		return -EIO;	}	rtnl_unlock();	MOD_INC_USE_COUNT;	DBFEXIT;	return 0;}/*----------------------------------------------------------------* unregister_wlandev** Roughly matches the functionality of unregister_netdev.  This* function is called to remove a named device from the system.** First we tell linux that the device should no longer exist.* Then we remove it from the list of known wlan devices.** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	zero on success, non-zero otherwise.* Call Context:*	Can be either interrupt or not.----------------------------------------------------------------*/int unregister_wlandev(wlandevice_t *wlandev){	DBFENTER;	rtnl_lock();	unregister_netdevice(wlandev->netdev);	wlandev_clear_index(wlandev);	rtnl_unlock();	MOD_DEC_USE_COUNT;	DBFEXIT;	return 0;}/*----------------------------------------------------------------* wlandev_get_index** Allocates a device number and constructs the name for the given * wlandev.  ** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	The device number on success, -1 otherwise* Side effects:*	The name is constructed in the space pointed to by wlandev->name.*	It had _better_ be a valid pointer.* Call Context:*	Can be either interrupt or not.----------------------------------------------------------------*/int wlandev_get_index(wlandevice_t  *wlandev){	int	i;	DBFENTER;	for  ( i = 0; i < MAX_WLAN_DEVICES; i++) {		if ( wlandev_index[i] == NULL ) {			sprintf(wlandev->name, "wlan%d", i);			WLAN_LOG_DEBUG1(1,"Loading device '%s'...\n", wlandev->name);			wlandev_index[i] = wlandev;			return i;		}	}	DBFEXIT;	return -1;}/*----------------------------------------------------------------* wlandev_clear_index** Frees a previously allocated device number.** Arguments:*	wlandev		ptr to the wlandev structure for the*			interface.* Returns: *	nothing* Side effects:*	none* Call Context:*	Can be either interrupt or not.----------------------------------------------------------------*/void wlandev_clear_index(wlandevice_t  *wlandev){	int	i;	DBFENTER;	for  ( i = 0; i < MAX_WLAN_DEVICES; i++) {		if ( wlandev_index[i] == wlandev ) {			wlandev_index[i] = NULL;		}	}	DBFEXIT;	return;}/*----------------------------------------------------------------* p80211netdev_hwremoved** Hardware removed notification. This function should be called* immediately after an MSD has detected that the underlying hardware* has been yanked out from under us.  The primary things we need* to do are:*   - Mark the wlandev*   - Prevent any further traffic from the knetdev i/f*   - Prevent any further requests from mgmt i/f*   - If there are any waitq'd mgmt requests or mgmt-frame exchanges,*     shut them down.*   - Call the MSD hwremoved function.** The remainder of the cleanup will be handled by unregister().* Our primary goal here is to prevent as much tickling of the MSD* as possible since the MSD is already in a 'wounded' state.** TODO: As new features are added, this function should be *       updated.** Arguments:*	wlandev		WLAN network device structure* Returns: *	nothing* Side effects:** Call context:*	Usually interrupt.----------------------------------------------------------------*/void p80211netdev_hwremoved(wlandevice_t *wlandev){	DBFENTER;	wlandev->hwremoved = 1;	if ( wlandev->state == WLAN_DEVICE_OPEN) {		p80211netdev_stop_queue(wlandev);	}	if (wlandev->hwremoved) {		(*(wlandev->hwremovedfn))(wlandev);	}	DBFEXIT;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?