📄 at76c503.c
字号:
/* -*- linux-c -*- *//* $Id: at76c503.c,v 1.35 2003/07/30 06:31:51 jal2 Exp $ * * USB at76c503/at76c505 driver * * Copyright (c) 2002 - 2003 Oliver Kurth <oku@masqmail.cx> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * History: * * 2002_12_31: * - first ping, ah-hoc mode works, fw version 0.90.2 only * * 2003_01_07 0.1: * - first release * * 2003_01_08 0.2: * - moved rx code into tasklet * - added locking in keventd handler * - support big endian in ieee802_11.h * - external firmware downloader now in this module * * 2003_01_10 0.3: * - now using 8 spaces for tab indentations * - added tx rate settings (patch from Joerg Albert (jal)) * - created functions for mib settings * * 2003_01_19 0.4: * - use usbdfu for the internal firmware * * 2003_01_27 0.5: * - implemented WEP. Thanks to jal * - added frag and rts ioctl calls (jal again) * - module parameter to give names other than eth * * 2003_01_28 0.6: * - make it compile with kernel < 2.4.20 (there is no owner field * in struct usb_driver) * - fixed a small bug for the module param eth_name * - do not use GFP_DMA, GFP_KERNEL is enough * - no down() in _tx() because that's in interrupt. Use * spin_lock_irq() instead * - should not stop net queue on urb errors * - cleanup in ioctl(): locked it altogether, this makes it easier * to maintain * - tried to implement promisc. mode: does not work with this device * - tried to implement setting mac address: does not * seem to work with this device * - now use fw version 0.90.2 #140 (prev. was #93). Does not help... * * 2003_01_30 0.7: * - now works with fw 0.100.2 (solution was: wait for completion * of commands) * - setting MAC address now works (thx to a small fix by jal) * - it turned out that promisc. mode is not possible. The firmware * does not allow it. I hope that it will be implemented in a future * version. * * 2003_02_13 0.8: * - scan mode implemented by jal * - infra structure mode by jal * - some small cleanups (removed dead code) * * history can now be found in the cvs log at http://at76c503a.berlios.de * * TODO: * - monitor mode * */#include <linux/config.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#include <linux/wireless.h>#include <linux/rtnetlink.h> /* for rtnl_lock() */#include "at76c503.h"#include "ieee802_11.h"/* debug bits */#define DBG_PROGRESS 0x000001 /* progress of scan-join-(auth-assoc)-connected */#define DBG_BSS_TABLE 0x000002 /* show the bss table after scans */#define DBG_IOCTL 0x000004 /* ioctl calls / settings */#define DBG_KEVENT 0x000008 /* kevents */#define DBG_TX_DATA 0x000010 /* tx header */#define DBG_TX_DATA_CONTENT 0x000020 /* tx content */#define DBG_TX_MGMT 0x000040#define DBG_RX_DATA 0x000080 /* rx data header */#define DBG_RX_DATA_CONTENT 0x000100 /* rx data content */#define DBG_RX_MGMT 0x000200 /* rx mgmt header except beacon and probe responses */#define DBG_RX_BEACON 0x000400 /* rx beacon */#define DBG_RX_CTRL 0x000800 /* rx control */#define DBG_RX_MGMT_CONTENT 0x001000 /* rx mgmt content */#define DBG_RX_FRAGS 0x002000 /* rx data fragment handling */#define DBG_DEVSTART 0x004000 /* fw download, device start */#define DBG_URB 0x008000 /* rx urb status, ... */#define DBG_RX_ATMEL_HDR 0x010000 /* the atmel specific header of each rx packet */#define DBG_PROC_ENTRY 0x020000 /* procedure entries and exits */#define DBG_PM 0x040000 /* power management settings */#define DBG_BSS_MATCH 0x080000 /* show why a certain bss did not match */#define DBG_PARAMS 0x100000 /* show the configured parameters */#define DBG_WAIT_COMPLETE 0x200000 /* show the wait_completion progress */#define DBG_RX_FRAGS_SKB 0x400000 /* show skb header for incoming rx fragments */#define DBG_BSS_TABLE_RM 0x800000 /* inform on removal of old bss table entries */#ifdef CONFIG_USB_DEBUG#define DBG_DEFAULTS (DBG_PROGRESS | DBG_PARAMS | DBG_BSS_TABLE)#else#define DBG_DEFAULTS 0#endifstatic int debug = DBG_DEFAULTS;static const u8 zeros[32];/* Use our own dbg macro */#undef dbg#define dbg(bits, format, arg...) \ do { \ if (debug & (bits)) \ printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg);\ } while (0)/* uncond. debug output */#define dbg_uc(format, arg...) \ printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)#ifndef min#define min(x,y) ((x) < (y) ? (x) : (y))#endif#define assert(x) \ do {\ if (!(x)) \ err(__FILE__ ":%d assertion " #x " failed", __LINE__);\ } while (0)/* how often do we re-try these packets ? */#define AUTH_RETRIES 3#define ASSOC_RETRIES 3#define DISASSOC_RETRIES 3#define NEW_STATE(dev,newstate) \ do {\ dbg(DBG_PROGRESS, "%s: state %d -> %d (" #newstate ")",\ dev->netdev->name, dev->istate, newstate);\ dev->istate = newstate;\ } while (0)/* the beacon timeout in infra mode when we are connected (in seconds) */#define BEACON_TIMEOUT 10/* after how many seconds do we re-scan the channels in infra mode */#define RESCAN_TIME 10/* Version Information */#define DRIVER_DESC "Generic Atmel at76c503/at76c505 routines"/* Module paramaters */MODULE_PARM(debug, "i");#define DRIVER_AUTHOR \"Oliver Kurth <oku@masqmail.cx>, Joerg Albert <joerg.albert@gmx.de>, Alex <alex@foogod.com>"MODULE_PARM_DESC(debug, "Debugging level");static int rx_copybreak = 200;MODULE_PARM(rx_copybreak, "i");MODULE_PARM_DESC(rx_copybreak, "rx packet copy threshold");static int scan_min_time = 10;MODULE_PARM(scan_min_time, "i");MODULE_PARM_DESC(scan_min_time, "scan min channel time (default: 10)");static int scan_max_time = 120;MODULE_PARM(scan_max_time, "i");MODULE_PARM_DESC(scan_max_time, "scan max channel time (default: 120)");static int scan_mode = SCAN_TYPE_ACTIVE;MODULE_PARM(scan_mode, "i");MODULE_PARM_DESC(scan_mode, "scan mode: 0 active (with ProbeReq, default), 1 passive");static int preamble_type = PREAMBLE_TYPE_LONG;MODULE_PARM(preamble_type, "i");MODULE_PARM_DESC(preamble_type, "preamble type: 0 long (default), 1 short");static int auth_mode = 0;MODULE_PARM(auth_mode, "i");MODULE_PARM_DESC(auth_mode, "authentication mode: 0 open system (default), " "1 shared secret");static int pm_mode = PM_ACTIVE;MODULE_PARM(pm_mode, "i");MODULE_PARM_DESC(pm_mode, "power management mode: 1 active (def.), 2 powersave, 3 smart save");static int pm_period = 0;MODULE_PARM(pm_period, "i");MODULE_PARM_DESC(pm_period, "period of waking up the device in usec");struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype;} __attribute__ ((packed));#define DEF_RTS_THRESHOLD 1536#define DEF_FRAG_THRESHOLD 1536#define DEF_ESSID "okuwlan"#define DEF_ESSID_LEN 7#define DEF_CHANNEL 10#define MAX_RTS_THRESHOLD 2347#define MAX_FRAG_THRESHOLD 2346#define MIN_FRAG_THRESHOLD 256/* The frequency of each channel in MHz */const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484};#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )/* the broadcast address */const u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};/* the supported rates of this hardware, bit7 marks a mandantory rate */const u8 hw_rates[4] = {0x82,0x84,0x0b,0x16};/* the max padding size for tx in bytes (see calc_padding)*/#define MAX_PADDING_SIZE 53/* a ieee820.11 frame header without addr4 */struct ieee802_11_mgmt { u16 frame_ctl; u16 duration_id; u8 addr1[ETH_ALEN]; /* destination addr */ u8 addr2[ETH_ALEN]; /* source addr */ u8 addr3[ETH_ALEN]; /* BSSID */ u16 seq_ctl; u8 data[1508]; u32 fcs;} __attribute__ ((packed));/* the size of the ieee802.11 header (excl. the at76c503 tx header) */#define IEEE802_11_MGMT_HEADER_SIZE offsetof(struct ieee802_11_mgmt, data)/* beacon in ieee802_11_mgmt.data */struct ieee802_11_beacon_data { u8 timestamp[8]; // TSFTIMER u16 beacon_interval; // Kms between TBTTs (Target Beacon Transmission Times) u16 capability_information; u8 data[1500]; /* contains: SSID (tag,length,value), Supported Rates (tlv), channel */} __attribute__ ((packed));/* disassoc frame in ieee802_11_mgmt.data */struct ieee802_11_disassoc_frame { u16 reason;} __attribute__ ((packed));#define DISASSOC_FRAME_SIZE \ (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ sizeof(struct ieee802_11_disassoc_frame))/* assoc request in ieee802_11_mgmt.data */struct ieee802_11_assoc_req { u16 capability; u16 listen_interval; u8 data[1]; /* variable number of bytes for SSID and supported rates (tlv coded) */};/* the maximum size of an AssocReq packet */#define ASSOCREQ_MAX_SIZE \ (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ offsetof(struct ieee802_11_assoc_req,data) +\ 1+1+IW_ESSID_MAX_SIZE + 1+1+4)/* reassoc request in ieee802_11_mgmt.data */struct ieee802_11_reassoc_req { u16 capability; u16 listen_interval; u8 curr_ap[ETH_ALEN]; /* the bssid of the AP we are currently associated to */ u8 data[1]; /* variable number of bytes for SSID and supported rates (tlv coded) */} __attribute__ ((packed));/* the maximum size of an AssocReq packet */#define REASSOCREQ_MAX_SIZE \ (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ offsetof(struct ieee802_11_reassoc_req,data) +\ 1+1+IW_ESSID_MAX_SIZE + 1+1+4)/* assoc/reassoc response */struct ieee802_11_assoc_resp { u16 capability; u16 status; u16 assoc_id; u8 data[1]; /* variable number of bytes for supported rates (tlv coded) */} __attribute__ ((packed));/* auth. request/response in ieee802_11_mgmt.data */struct ieee802_11_auth_frame { u16 algorithm; u16 seq_nr; u16 status; u8 challenge[0];} __attribute__ ((packed));/* for shared secret auth, add the challenge text size */#define AUTH_FRAME_SIZE \ (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ sizeof(struct ieee802_11_auth_frame))/* deauth frame in ieee802_11_mgmt.data */struct ieee802_11_deauth_frame { u16 reason;} __attribute__ ((packed));#define DEAUTH_FRAME_SIZE \ (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ sizeof(struct ieee802_11_disauth_frame))#define KEVENT_CTRL_HALT 1#define KEVENT_NEW_BSS 2#define KEVENT_SET_PROMISC 3#define KEVENT_MGMT_TIMEOUT 4#define KEVENT_SCAN 5 #define KEVENT_JOIN 6#define KEVENT_STARTIBSS 7#define KEVENT_SUBMIT_RX 8#define KEVENT_RESTART 9 /* restart the device */#define KEVENT_ASSOC_DONE 10 /* execute the power save settings: listen interval, pm mode, assoc id */static DECLARE_WAIT_QUEUE_HEAD(wait_queue);static u8 snapsig[] = {0xaa, 0xaa, 0x03};#ifdef COLLAPSE_RFC1042/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with * a SNAP OID of 0 (0x00, 0x00, 0x00) */static u8 rfc1042sig[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};#endif /* COLLAPSE_RFC1042 *//* local function prototypes */ #if IW_MAX_SPY > 0static void iwspy_update(struct at76c503 *dev, struct at76c503_rx_buffer *buf);#endifstatic void at76c503_read_bulk_callback (struct urb *urb);static void at76c503_write_bulk_callback(struct urb *urb);static void defer_kevent (struct at76c503 *dev, int flag);static struct bss_info *find_matching_bss(struct at76c503 *dev, struct bss_info *curr);static int auth_req(struct at76c503 *dev, struct bss_info *bss, int seq_nr, u8 *challenge);static int disassoc_req(struct at76c503 *dev, struct bss_info *bss);static int assoc_req(struct at76c503 *dev, struct bss_info *bss);static int reassoc_req(struct at76c503 *dev, struct bss_info *curr, struct bss_info *new);static void dump_bss_table(struct at76c503 *dev, int force_output);static int submit_rx_urb(struct at76c503 *dev);static int startup_device(struct at76c503 *dev);/* hexdump len many bytes from buf into obuf, separated by delim, add a trailing \0 into obuf */static char *hex2str(char *obuf, u8 *buf, int len, char delim){#define BIN2HEX(x) ((x) < 10 ? '0'+(x) : (x)+'A'-10) char *ret = obuf; while (len--) { *obuf++ = BIN2HEX(*buf>>4); *obuf++ = BIN2HEX(*buf&0xf); if (delim != '\0') *obuf++ = delim; buf++; } if (delim != '\0' && obuf > ret) obuf--; // remove last inserted delimiter *obuf = '\0'; return ret;}static inline void free_bss_list(struct at76c503 *dev){ struct list_head *next, *ptr; unsigned long flags; spin_lock_irqsave(&dev->bss_list_spinlock, flags); dev->curr_bss = dev->new_bss = NULL; list_for_each_safe(ptr, next, &dev->bss_list) { list_del(ptr); kfree(list_entry(ptr, struct bss_info, list)); } spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);}static inline char *mac2str(u8 *mac){ static char str [6*3]; sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return str;}static inline void usb_debug_data (const char *function, const unsigned char *data, int size){ int i; if (!debug) return; printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size); for (i = 0; i < size; ++i) { if((i % 8) == 0) printk ("\n"); printk ("%.2x ", data[i]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -