p80211netdev.c

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

C
1,046
字号
/* src/p80211/p80211knetdev.c** Linux Kernel net device interface** Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.* --------------------------------------------------------------------** linux-wlan**   The contents of this file are subject to the Mozilla Public*   License Version 1.1 (the "License"); you may not use this file*   except in compliance with the License. You may obtain a copy of*   the License at http://www.mozilla.org/MPL/**   Software distributed under the License is distributed on an "AS*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or*   implied. See the License for the specific language governing*   rights and limitations under the License.**   Alternatively, the contents of this file may be used under the*   terms of the GNU Public License version 2 (the "GPL"), in which*   case the provisions of the GPL are applicable instead of the*   above.  If you wish to allow the use of your version of this file*   only under the terms of the GPL and not to allow others to use*   your version of this file under the MPL, indicate your decision*   by deleting the provisions above and replace them with the notice*   and other provisions required by the GPL.  If you do not delete*   the provisions above, a recipient may use your version of this*   file under either the MPL or the GPL.** --------------------------------------------------------------------** Inquiries regarding the linux-wlan Open Source project can be* made directly to:** AbsoluteValue Systems Inc.* info@linux-wlan.com* http://www.linux-wlan.com** --------------------------------------------------------------------** Portions of the development of this software were funded by * Intersil Corporation as part of PRISM(R) chipset product development.** --------------------------------------------------------------------** The functions required for a Linux network device are defined here.** --------------------------------------------------------------------*//*================================================================*//* System Includes */#define __NO_VERSION__		/* prevent the static definition */#include <linux/config.h>#include <linux/version.h>#include <wlan/wlan_compat.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/netdevice.h>#include <linux/rtnetlink.h>#include <linux/etherdevice.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/byteorder.h>/*================================================================*//* Project Includes */#include <wlan/version.h>#include <wlan/p80211types.h>#include <wlan/p80211hdr.h>#include <wlan/p80211conv.h>#include <wlan/p80211mgmt.h>#include <wlan/p80211msg.h>#include <wlan/p80211netdev.h>#include <wlan/p80211ioctl.h>#include <wlan/p80211req.h>#include <wlan/p80211metastruct.h>#include <wlan/p80211metadef.h>/*================================================================*//* Local Constants */#define MAX_WLAN_DEVICES	4	/* At most 3 non-intefering DS cards *//*================================================================*//* Local Macros *//*================================================================*//* Local Types *//*================================================================*//* Local Static Definitions */static wlandevice_t	*wlandev_index[MAX_WLAN_DEVICES];/*================================================================*//* Local Function Declarations *//* Support functions */static int wlandev_get_index(wlandevice_t  *wlandev);static void wlandev_clear_index(wlandevice_t  *wlandev);/* netdevice method functions */static int p80211knetdev_init( netdevice_t *netdev);static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev);static int p80211knetdev_open( netdevice_t *netdev);static int p80211knetdev_stop( netdevice_t *netdev );static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev);static void p80211knetdev_set_multicast_list(netdevice_t *dev);static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd);static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr);/*================================================================*//* Function Definitions *//*----------------------------------------------------------------* p80211knetdev_startup** Initialize the wlandevice/netdevice part of 802.11 services at * load time.** Arguments:*	none** Returns: *	nothing----------------------------------------------------------------*/void p80211netdev_startup(void){	DBFENTER;	memset( wlandev_index, 0, sizeof(wlandev_index));	DBFEXIT;	return;}/*----------------------------------------------------------------* p80211knetdev_init** Init method for a Linux netdevice.  Called in response to* register_netdev.** Arguments:*	none** Returns: *	nothing----------------------------------------------------------------*/int p80211knetdev_init( netdevice_t *netdev){	DBFENTER;	/* Called in response to register_netdev */	/* This is usually the probe function, but the probe has */	/* already been done by the MSD and the create_kdev */	/* function.  All we do here is return success */	DBFEXIT;	return 0;}/*----------------------------------------------------------------* p80211knetdev_get_stats** Statistics retrieval for linux netdevices.  Here we're reporting* the Linux i/f level statistics.  Hence, for the primary numbers,* we don't want to report the numbers from the MIB.  Eventually,* it might be useful to collect some of the error counters though.** Arguments:*	netdev		Linux netdevice** Returns: *	the address of the statistics structure----------------------------------------------------------------*/struct net_device_stats*p80211knetdev_get_stats(netdevice_t *netdev){	wlandevice_t	*wlandev = (wlandevice_t*)netdev->priv;	DBFENTER;	/* TODO: review the MIB stats for items that correspond to 		linux stats */	DBFEXIT;	return &(wlandev->linux_stats);}/*----------------------------------------------------------------* p80211knetdev_open** Linux netdevice open method.  Following a successful call here,* the device is supposed to be ready for tx and rx.  In our* situation that may not be entirely true due to the state of the* MAC below.** Arguments:*	netdev		Linux network device structure** Returns: *	zero on success, non-zero otherwise----------------------------------------------------------------*/int p80211knetdev_open( netdevice_t *netdev ){	int 		result = 0; /* success */	wlandevice_t	*wlandev = (wlandevice_t*)(netdev->priv);	DBFENTER;	/* Check to make sure the MSD is running */	if ( wlandev->msdstate != WLAN_MSD_RUNNING ) {		return -ENODEV;	}	/* Tell the MSD to open */	if ( wlandev->open != NULL) {		result = (*(wlandev->open))(wlandev);		if ( result == 0 ) {#if ( LINUX_VERSION_CODE < WLAN_KVERSION(2,3,43) )			netdev->interrupt = 0;#endif			p80211netdev_start_queue(wlandev);			wlandev->state = WLAN_DEVICE_OPEN;		}	} else {		result = -EAGAIN;	}	DBFEXIT;	return result;}/*----------------------------------------------------------------* p80211knetdev_stop** Linux netdevice stop (close) method.  Following this call,* no frames should go up or down through this interface.** Arguments:*	netdev		Linux network device structure** Returns: *	zero on success, non-zero otherwise----------------------------------------------------------------*/int p80211knetdev_stop( netdevice_t *netdev ){	int		result = 0;	wlandevice_t	*wlandev = (wlandevice_t*)(netdev->priv);	DBFENTER;	if ( wlandev->close != NULL ) {		result = (*(wlandev->close))(wlandev);	}	p80211netdev_stop_queue(wlandev);	wlandev->state = WLAN_DEVICE_CLOSED;	DBFEXIT;	return result;}/*----------------------------------------------------------------* p80211netdev_rx** Frame receive function called by the mac specific driver.** Arguments:*	wlandev		WLAN network device structure*	pb		WLAN packet buffer containing an 802.11*			frame.* Returns: *	nothing* Side effects:*	Whoever allocates pb should also ree it.----------------------------------------------------------------*/void p80211netdev_rx(wlandevice_t *wlandev, wlan_pb_t *pb){	netdevice_t	*dev = wlandev->netdev;        struct sk_buff  *skb;        DBFENTER;        if (wlandev->state == WLAN_DEVICE_OPEN) {		if ( pb->p80211_payloadlen == 0 ) {			/* Do nothing, converting and passing up zero 			   length frame is pointless 			*/		} else if ( p80211pb_p80211_to_ether(wlandev, wlandev->ethconv, pb) == 0 ) {                        /* Mark last reception */                        dev->last_rx = jiffies;                        /* take ownership of skb from pb */                        skb = (struct sk_buff*)pb->ethhostbuf;                        pb->ethhostbuf = NULL;                        pb->ethfree = NULL;                        skb->dev = dev;                        skb->protocol = eth_type_trans( skb, dev);                        netif_rx(skb);			wlandev->linux_stats.rx_packets++;			/* count only the packet payload */			wlandev->linux_stats.rx_bytes += skb->len;                } else {			WLAN_LOG_DEBUG0(1, "p80211_to_ether failed.\n");		}	}        DBFEXIT;} /*----------------------------------------------------------------* p80211knetdev_hard_start_xmit** Linux netdevice method for transmitting a frame.** Arguments:*	skb	Linux sk_buff containing the frame.*	netdev	Linux netdevice.** Side effects:*	If the lower layers report that buffers are full. netdev->tbusy*	will be set to prevent higher layers from sending more traffic.**	Note: If this function returns non-zero, higher layers retain*	      ownership of the skb.** Returns: *	zero on success, non-zero on failure.----------------------------------------------------------------*/int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev){	int		result = 0;	int		txresult = -1;	wlan_pb_t	*pb;	wlandevice_t	*wlandev = (wlandevice_t*)netdev->priv;	DBFENTER;	if (skb == NULL ) {		return 0;	}        if (wlandev->state != WLAN_DEVICE_OPEN) {		return 1;	}#if (LINUX_VERSION_CODE < WLAN_KVERSION(2,3,38) )	if ( test_and_set_bit(0, (void*)&(netdev->tbusy)) != 0 ) {		/* We've been called w/ tbusy set, has the tx */		/* path stalled?   */		WLAN_LOG_DEBUG0(1, "called when tbusy set\n");		return 1;	} #else	netif_stop_queue(netdev);	/* No timeout handling here, 2.3.38+ kernels call the 	 * timeout function directly.	 * TODO: Add timeout handling.	*/#endif	/* particularly handy in the above case */	netdev->trans_start = jiffies;	/* Check to see that a valid mode is set */	switch( wlandev->macmode ) {	case WLAN_MACMODE_IBSS_STA: 	case WLAN_MACMODE_ESS_STA:	case WLAN_MACMODE_ESS_AP:		break;	default:		/* Mode isn't set yet, just drop the frame 		 * and return success .		 * TODO: we need a saner way to handle this 		 */	  if(skb->protocol != ETH_P_80211_RAW) {		p80211netdev_wake_queue(wlandev);		dev_kfree_skb(skb);		WLAN_LOG_NOTICE0(			"Tx attempt prior to association, frame dropped.\n");		return 0;	  }		break;	}			/* OK, now we setup the ether to 802.11 conversion */	pb = p80211pb_alloc();	if ( pb == NULL ) {		return 1;	}#ifdef CONFIG_PACKET	/* Check for raw transmits */	pb->ethfree = p80211pb_freeskb;	if(skb->protocol == ETH_P_80211_RAW) {	  if (!capable(CAP_NET_ADMIN)) {	    return(-EPERM);	  }	  pb->ethhostbuf = NULL; /* we have to set this to NULL to tell txframe its raw */	  pb->p80211buf = pb->p80211_payload = skb->data;	  pb->p80211buflen = skb->len > 1514 ? 1514 : skb->len;	} else {#endif	  pb->ethhostbuf = skb;	  pb->ethfree = p80211pb_freeskb;	  pb->ethbuf = skb->data;	  pb->ethbuflen = skb->len > 1514 ? 1514 : skb->len;	  pb->ethfrmlen = pb->ethbuflen;	  pb->eth_hdr = (wlan_ethhdr_t*)pb->ethbuf;	  if ( p80211pb_ether_to_p80211(wlandev, wlandev->ethconv, pb) != 0 ) {	    /* convert failed */	    WLAN_LOG_DEBUG1(1, 			    "ether_to_80211(%d) failed.\n", 			    wlandev->ethconv);	    /* Free the pb, but not the skb */	    pb->ethhostbuf = NULL;	    result = 1;	    goto failed;	  }#ifdef CONFIG_PACKET	}#endif	if ( wlandev->txframe == NULL ) {		/* Free the pb, but not the skb */		pb->ethhostbuf = NULL;		result = 1;		goto failed;	}	wlandev->linux_stats.tx_packets++;	/* count only the packet payload */	wlandev->linux_stats.tx_bytes += skb->len;		txresult = (*(wlandev->txframe))(wlandev, pb);	if ( txresult == 0) {		/* success and more buf */		/* avail, re: hw_txdata */		p80211netdev_wake_queue(wlandev);		result = 0;	} else if ( txresult == 1 ) { 		/* success, no more avail */		WLAN_LOG_DEBUG0(3, "txframe success, no more bufs\n");		/* netdev->tbusy = 1;  don't set here, irqhdlr */		/*   may have already cleared it */		result = 0;	} else if ( txresult == 2 ) { 		/* alloc failure, drop frame */		WLAN_LOG_DEBUG0(3, "txframe returned alloc_fail\n");		p80211netdev_wake_queue(wlandev);		/* Free the pb, but not the skb */		pb->ethhostbuf = NULL;		result = 1;	} else { 		/* buffer full or queue busy */		WLAN_LOG_DEBUG0(3, "txframe returned full or busy\n");		p80211netdev_wake_queue(wlandev);		/* Free the pb, but not the skb */		pb->ethhostbuf = NULL;		result = 1;	}failed:	/* As far as I know pb should always be freed. */	p80211pb_free(pb);	DBFEXIT;	return result;}/*----------------------------------------------------------------* p80211knetdev_set_multicast_list** Called from higher lavers whenever there's a need to set/clear* promiscuous mode or rewrite the multicast list.** Arguments:*	none** Returns: *	nothing----------------------------------------------------------------*/void p80211knetdev_set_multicast_list(netdevice_t *dev){  /* TODO:  real multicast support as well */        wlandevice_t    *wlandev = (wlandevice_t*)dev->priv;	p80211msg_dot11req_mibset_t     msg;	p80211item_uint32_t             mibitem;	UINT32          arg;	int             result;	int             doPromisc = 0;		DBFENTER;		if (dev->flags & IFF_ALLMULTI) {  	  /* Set a MIB for 'allmulti_rx'?  */	  doPromisc = 1;	}	if (dev->flags & IFF_PROMISC) {	  doPromisc = 1;	}        mibitem.did = DIDmib_p2_p2Dynamic_p2PromiscuousMode;        mibitem.status = (UINT16) P80211ENUM_msgitem_status_data_ok;         msg.msgcode = DIDmsg_dot11req_mibset;

⌨️ 快捷键说明

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