📄 am930llc.c
字号:
/* am930llc.c: Handles the Linux network interface* --------------------------------------------------------------------** Linux WLAN ** The contents of this file are subject to the Mozilla Public* License Version 1.0 (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.** The initial developer of the original code is Mark S. Mathews* <mark@absoval.com>. Portions created by Mark S. Mathews* are Copyright (C) 1998 AbsoluteValue Software, Inc. All Rights Reserved.* * --------------------------------------------------------------------** The author may be reached as mark@absoval.com, or C/O AbsoluteValue* Software Inc., P.O. Box 941149, Maitland, FL, 32794-1149** Thanks to David Hinds, Donald Becker, and the rest of the Linux* developers worldwide for making all of this possible.** --------------------------------------------------------------------** Seperate file isolating the functions that handle the Linux network* interface. LLC may not be the appropriate name, but this code _does_* sit on top of the MAC...**/#include <linux/config.h>#include <wlan/wlan_compat.h>/* The following prevents "kernel_version" from being set in this file. */#define __NO_VERSION__/* PCMCIA headers generated during PCMCIA package installation */#ifdef WLAN_PCMCIA#include <pcmcia/config.h>#include <pcmcia/k_compat.h>#endif/* Module related headers, non-module drivers should not include */#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>/* Ethernet and network includes */#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/ioport.h>#include <net/sock.h>#include <linux/netlink.h>/* Standard driver includes */#include <linux/delay.h>#include <linux/types.h>#include <linux/fcntl.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/in.h>#include <linux/ptrace.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>/* Card and Driver services includes */#ifdef WLAN_PCMCIA#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/ds.h>#include <pcmcia/cisreg.h>#endif/* Local Includes */#include <wlan/version.h>#include <wlan/wlan_compat.h>#include <wlan/am930mib.h>#include <wlan/wlan_ioctl.h>#ifdef WLAN_PCMCIA#include "am930di.h"#endif#include "am930llc.h"#include "am930mac.h"#include "am930hw.h"#include "am930mgr.h"/*================================================================*//* Local Macros */#define WLAN_DEVNAME_LEN 9/*================================================================*//* Local Types */#if LINUX_VERSION_CODE <= 0x20139typedef struct enet_statistics enet_stats_t;#elsetypedef struct net_device_stats enet_stats_t;#endiftypedef struct devpriv{ enet_stats_t stats; am930llc_t* llc;} devpriv_t;typedef int (*do_ioctl_t)(device_t *dev, struct ifreq *ifr, int cmd);typedef void (*timerfunc_t)(unsigned long);/*================================================================*//* Local Functions */static int am930llc_devinit(device_t *dev);static int am930llc_devopen(device_t *dev);static int am930llc_devstop(device_t *dev);static int am930llc_devhard_start_xmit( struct sk_buff *skb, device_t *dev);static enet_stats_t* am930llc_devgetstats(device_t *dev);static void am930llc_devset_multicast_list(device_t *dev);static int am930llc_devdo_ioctl(device_t *dev, wlan_req_t *req, int cmd);void am930llc_timerfunc(am930llc_t *llc);void am930llc_cmdtimerfunc(am930llc_t *llc);void am930llc_nlfunc(struct sock *sk, int len);/*================================================================*//* Static variables */UINT8 oui_rfc1042[] = {0x00, 0x00, 0x00};UINT8 oui_8021h[] = {0x00, 0x00, 0xf8};/*================================================================*//*----------------------------------------------------------------* am930llc_construct** returns: addr. of the lnd object if successful, NULL otherwise----------------------------------------------------------------*/am930llc_t *am930llc_construct(am930mac_t *mac, am930mgr_t *mgr){ am930llc_t *llc; DBFENTER; llc = kmalloc( sizeof(am930llc_t), GFP_KERNEL); if ( llc != NULL ) { memset( llc, 0, sizeof(am930llc_t)); llc->mac = mac; llc->mgr = mgr; llc->ethconv = WLAN_ETHCONV_ENCAP; /* set by user later */ /* lets begin the initialization of the linux device */ llc->dev = kmalloc( sizeof(device_t), GFP_KERNEL); if ( llc->dev == NULL ) { kfree_s(llc, sizeof(am930llc_t)); return NULL; } memset( llc->dev, 0, sizeof(device_t)); llc->dev->priv = kmalloc( sizeof(devpriv_t), GFP_KERNEL); if ( llc->dev->priv == NULL ) { kfree_s(llc->dev, sizeof(device_t)); kfree_s(llc, sizeof(am930llc_t)); return NULL; } memset( llc->dev->priv, 0, sizeof(devpriv_t)); /* the dev name field will point to the same memory used by the node_t field of the pcmcia di object */ #ifdef WLAN_PCMCIA llc->dev->name = ((dev_link_t*)(llc->mac->di))->dev->dev_name; #else llc->dev->name = kmalloc(WLAN_DEVNAME_LEN, GFP_KERNEL); if ( llc->dev->name == NULL ) { WLAN_LOG_ERROR0("Failed to alloc device name space.\n"); kfree_s( llc->dev->priv, sizeof(devpriv_t)); kfree_s( llc->dev, sizeof(device_t)); kfree_s( llc, sizeof(am930llc_t)); return NULL; } llc->dev->name[0] = '\0'; #endif /* set the private data to point back at the llc */ V2P(llc->dev->priv)->llc = llc; /* set the hardware address */ am930mgr_mibgetitem( llc->mgr, ADDR_MAC_ADDR, llc->dev->dev_addr, 6); /* set the method pointers */ llc->dev->init = am930llc_devinit; llc->dev->open = am930llc_devopen; llc->dev->stop = am930llc_devstop; llc->dev->hard_start_xmit = am930llc_devhard_start_xmit; llc->dev->get_stats = am930llc_devgetstats; llc->dev->set_multicast_list = am930llc_devset_multicast_list; llc->dev->do_ioctl = (do_ioctl_t)am930llc_devdo_ioctl; ether_setup( llc->dev ); if ( register_netdev(llc->dev) != 0 ) { WLAN_LOG_ERROR0("register_netdev failed!\n"); kfree( llc->dev ); llc->dev = NULL; am930llc_destruct( llc ); llc = NULL; } WLAN_LOG_INFO1("Device %s registered\n", llc->dev->name);#if 0 /* now set up the kernel timer */ init_timer(&llc->timer); llc->timer.data = (unsigned long)llc; llc->timer.function = (timerfunc_t)am930llc_timerfunc; llc->timer.expires = jiffies + (HZ / 10); add_timer(&llc->timer);#endif /* set up the netlink i/f for a potential sniffer */ llc->nlsk = netlink_kernel_create( NETLINK_USERSOCK, am930llc_nlfunc); if ( llc->nlsk == NULL ) { WLAN_LOG_WARNING0("Failed to create netlink i/f.\n"); } } DBFEXIT return llc;} /*----------------------------------------------------------------* am930llc_cmdtimerfunc* One shot timer func called when an ioctl command has timed out.** returns: nothing----------------------------------------------------------------*/void am930llc_cmdtimerfunc(am930llc_t *llc){ DBFENTER; /* clear the expires field as a flag that we've timed out */ llc->timer.expires = 0; /* Assume the timer was set up to watch us while an ioctl's in */ /* the wait queue. Check for NULL and if not, wake it */ if ( llc->cmdwq != NULL ){ wake_up_interruptible(&(llc->cmdwq)); } DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_timerfunc* Called 10 times per second. Calls any timer functions* established by the other components.** returns: nothing----------------------------------------------------------------*/void am930llc_timerfunc(am930llc_t *llc){ DBFENTER; if ( llc->mac != NULL && llc->mac->timerfunc != NULL ) { (*llc->mac->timerfunc)(llc->mac); if ( llc->mac->hw != NULL && llc->mac->hw->timerfunc != NULL ) { (*llc->mac->hw->timerfunc)(llc->mac->hw); } } if ( llc->mgr != NULL && llc->mgr->timerfunc != NULL ) { (*llc->mgr->timerfunc)(llc->mgr); } init_timer(&llc->timer); llc->timer.data = (unsigned long)llc; llc->timer.function = (timerfunc_t)am930llc_timerfunc; llc->timer.expires = jiffies + (HZ / 10); add_timer(&llc->timer); DBFEXIT;}/*----------------------------------------------------------------* am930llc_destruct** returns: nothing----------------------------------------------------------------*/void am930llc_destruct( am930llc_t *llc){ DBFENTER; if ( llc->dev != NULL ) { del_timer(&llc->timer); llc->dev->start = 0; unregister_netdev( llc->dev ); kfree(llc->dev); llc->dev = NULL; } kfree_s( llc, sizeof(am930llc_t)); DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_devinit* init method for the linux net device. Called by * register_netdevice. For this driver, it doesn't have to do* anything.** returns: zero----------------------------------------------------------------*/int am930llc_devinit(device_t *dev){ int result = 0; DBFENTER; DBFEXIT; return result;}/*----------------------------------------------------------------* am930llc_cmdcomplete* Called by mgr whenever one of our asynch commands * (scan, auth,assoc,etc.) finishes. Our primary responsibility* here is to wake up any waiting process (blocked in ioctl).* See also: cmdtimerfunc** returns: nothing----------------------------------------------------------------*/void am930llc_cmdcomplete(am930llc_t *llc, UINT status){ DBFENTER; if ( llc->cmdwq != NULL ){ llc->cmdstatus = status; wake_up_interruptible(&(llc->cmdwq)); } DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_devdo_ioctl* do_ioctl method for the linux net device. Private ioctl handler* for the net device. Used here to pass commands to the mgr* object.* TODO: Define the interface between the mgr object and user* mode utilities. ** returns: zero----------------------------------------------------------------*/int am930llc_devdo_ioctl(device_t *dev, wlan_req_t *req, int cmd){ int result = 0; am930llc_t *llc = V2P(dev->priv)->llc; DBFENTER; /* According to Alan, we're supposed to check the req ptr and data area */ /* here, but aside from a NULL check, I'm not quite sure how. */ /* Now that we have the blocks and timers, etc. We should sync access */ if ( req == NULL ) { result = -EFAULT; } else { if ( test_and_set_bit( 0, (void*)&(llc->cmdbusy))) { return -EBUSY; } llc->currcmd = cmd; switch( cmd ) { case WLAN_TEST: req->result = 0xf0f0; break; case WLAN_SCAN: { wlan_scan_t cmd; UINT32 timeout = HZ; /* default 1 second */ UINT32 scanticks = 0; if ( copy_from_user( &cmd, req->data, sizeof(cmd)) ) { result = -EFAULT; break; } /* Call mgr to begin the scan */ req->result = am930mgr_scanbegin( llc->mgr, cmd.scantype, /*active/passive*/ cmd.bsstype, /*ind./infra./both*/ cmd.bssid, /*bcast/specific*/ cmd.startch, cmd.endch, cmd.timech, /*time per ch.*/ (wlan_ie_ssid_t*)cmd.ssid); /* Set a timer for (timech * nchannels + slop) to make */ /* sure we return */ scanticks = wlan_tu2ticks(((cmd.endch-cmd.startch)*cmd.timech)); scanticks += (HZ/5); /* a little extra for slop */ if ( scanticks > timeout ) { timeout = scanticks; } init_timer(&llc->cmdtimer); llc->cmdtimer.data = (unsigned long)llc; llc->cmdtimer.function = (timerfunc_t)am930llc_cmdtimerfunc; llc->cmdtimer.expires = jiffies + timeout; add_timer(&llc->cmdtimer); /* Now, do an interruptible_sleep, we'll be awakened by: */ /* a signal the process, cmdtimerfunc (timeout), or llc_scancomplete */ interruptible_sleep_on(&(llc->cmdwq)); llc->cmdwq = NULL; /* If sleep return is via signal */ if ( signal_pending(current) ) { WLAN_LOG_DEBUG0(2,"Scan unblocked via signal\n"); /* stop scan, clean up scan and timer */ am930mgr_scanstop(llc->mgr); del_timer(&llc->cmdtimer); result = -EINTR; } else { /* If timeout */ if ( llc->cmdtimer.expires == 0 ) { WLAN_LOG_DEBUG0(2,"Scan unblocked via timeout\n"); /* stop scan, clean up scan */ am930mgr_scanstop(llc->mgr); result = -ETIME; } else { /* Success */ /* clean up timer */ del_timer(&llc->cmdtimer); llc->cmdtimer.expires=0; req->result = llc->cmdstatus; /* return success */ result = 0; } } break; } case WLAN_NETLIST_LEN: { wlan_netlist_len_t cmd; knownbss_t *curr; int i; am930mgr_t* mgr = llc->mgr; i = 0; for( curr = mgr->bsslist; curr != NULL; curr = curr->next) { i++; } cmd.nitems = i; if ( copy_to_user( req->data, &cmd, sizeof(cmd)) ) { result = -EFAULT; } req->result = 0; break; } case WLAN_NETLIST: { wlan_netlist_t *cmd; wlan_netlist_t tmp; knownbss_t *curr; wlan_ie_ssid_t *ie; int i; am930mgr_t* mgr = llc->mgr; if ( copy_from_user( &tmp, req->data, sizeof(tmp)) ) { result = -EFAULT; break; } cmd = kmalloc(sizeof(wlan_netlist_t) + (tmp.nitems * sizeof(netitem_t)), GFP_ATOMIC); if ( cmd == NULL ) { result = -ENOMEM; break; } cmd->nitems = tmp.nitems; i = 0; for( curr = mgr->bsslist; curr != NULL; curr = curr->next) { cmd->netlist[i].channel = curr->channel; cmd->netlist[i].bcn_int = curr->bcn_int; cmd->netlist[i].cap_info = curr->cap_info; memcpy(cmd->netlist[i].bssid, curr->bssid, 6); ie = (wlan_ie_ssid_t*)curr->ssid; memcpy(cmd->netlist[i].ssid, ie, ie->len + 2); i++; } if ( copy_to_user( req->data, cmd, sizeof(wlan_netlist_t) + (cmd->nitems * sizeof(netitem_t))) ) { result = -EFAULT; } kfree_s(cmd, sizeof(wlan_netlist_t)+(tmp.nitems*sizeof(netitem_t))); break; } case WLAN_BSSCREATE: { wlan_bsscreate_t cmd; if (copy_from_user( &cmd, req->data, sizeof(cmd))) { result = -EFAULT; break; } req->result = am930mgr_createbss( llc->mgr, cmd.channel,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -