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 + -
显示快捷键?