···47274727 StatsRid stats;47284728 int i, j;47294729 __le32 *vals = stats.vals;47304730- int len = le16_to_cpu(stats.len);47304730+ int len;4731473147324732 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)47334733 return -ENOMEM;···47384738 }4739473947404740 readStatsRid(apriv, &stats, rid, 1);47414741+ len = le16_to_cpu(stats.len);4741474247424743 j = 0;47434744 for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
+2501
drivers/net/wireless/at76c50x-usb.c
···11+/*22+ * at76c503/at76c505 USB driver33+ *44+ * Copyright (c) 2002 - 2003 Oliver Kurth55+ * Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de>66+ * Copyright (c) 2004 Nick Jones77+ * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>88+ * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>99+ * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>1010+ *1111+ * This program is free software; you can redistribute it and/or1212+ * modify it under the terms of the GNU General Public License as1313+ * published by the Free Software Foundation; either version 2 of1414+ * the License, or (at your option) any later version.1515+ *1616+ * This file is part of the Berlios driver for WLAN USB devices based on the1717+ * Atmel AT76C503A/505/505A.1818+ *1919+ * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed2020+ *2121+ * TODO list is at the wiki:2222+ *2323+ * http://wireless.kernel.org/en/users/Drivers/at76c50x-usb#TODO2424+ *2525+ */2626+2727+#include <linux/init.h>2828+#include <linux/kernel.h>2929+#include <linux/sched.h>3030+#include <linux/errno.h>3131+#include <linux/slab.h>3232+#include <linux/module.h>3333+#include <linux/spinlock.h>3434+#include <linux/list.h>3535+#include <linux/usb.h>3636+#include <linux/netdevice.h>3737+#include <linux/if_arp.h>3838+#include <linux/etherdevice.h>3939+#include <linux/ethtool.h>4040+#include <linux/wireless.h>4141+#include <net/iw_handler.h>4242+#include <net/ieee80211_radiotap.h>4343+#include <linux/firmware.h>4444+#include <linux/leds.h>4545+#include <net/mac80211.h>4646+4747+#include "at76c50x-usb.h"4848+4949+/* Version information */5050+#define DRIVER_NAME "at76c50x-usb"5151+#define DRIVER_VERSION "0.17"5252+#define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver"5353+5454+/* at76_debug bits */5555+#define DBG_PROGRESS 0x00000001 /* authentication/accociation */5656+#define DBG_BSS_TABLE 0x00000002 /* show BSS table after scans */5757+#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */5858+#define DBG_MAC_STATE 0x00000008 /* MAC state transitions */5959+#define DBG_TX_DATA 0x00000010 /* tx header */6060+#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */6161+#define DBG_TX_MGMT 0x00000040 /* tx management */6262+#define DBG_RX_DATA 0x00000080 /* rx data header */6363+#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */6464+#define DBG_RX_MGMT 0x00000200 /* rx mgmt frame headers */6565+#define DBG_RX_BEACON 0x00000400 /* rx beacon */6666+#define DBG_RX_CTRL 0x00000800 /* rx control */6767+#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */6868+#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */6969+#define DBG_DEVSTART 0x00004000 /* fw download, device start */7070+#define DBG_URB 0x00008000 /* rx urb status, ... */7171+#define DBG_RX_ATMEL_HDR 0x00010000 /* Atmel-specific Rx headers */7272+#define DBG_PROC_ENTRY 0x00020000 /* procedure entries/exits */7373+#define DBG_PM 0x00040000 /* power management settings */7474+#define DBG_BSS_MATCH 0x00080000 /* BSS match failures */7575+#define DBG_PARAMS 0x00100000 /* show configured parameters */7676+#define DBG_WAIT_COMPLETE 0x00200000 /* command completion */7777+#define DBG_RX_FRAGS_SKB 0x00400000 /* skb header of Rx fragments */7878+#define DBG_BSS_TABLE_RM 0x00800000 /* purging bss table entries */7979+#define DBG_MONITOR_MODE 0x01000000 /* monitor mode */8080+#define DBG_MIB 0x02000000 /* dump all MIBs on startup */8181+#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */8282+#define DBG_WE_EVENTS 0x08000000 /* dump wireless events */8383+#define DBG_FW 0x10000000 /* firmware download */8484+#define DBG_DFU 0x20000000 /* device firmware upgrade */8585+#define DBG_CMD 0x400000008686+#define DBG_MAC80211 0x800000008787+8888+#define DBG_DEFAULTS 08989+9090+/* Use our own dbg macro */9191+#define at76_dbg(bits, format, arg...) \9292+ do { \9393+ if (at76_debug & (bits)) \9494+ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \9595+ ## arg); \9696+ } while (0)9797+9898+#define at76_dbg_dump(bits, buf, len, format, arg...) \9999+ do { \100100+ if (at76_debug & (bits)) { \101101+ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \102102+ ## arg); \103103+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, \104104+ buf, len); \105105+ } \106106+ } while (0)107107+108108+static uint at76_debug = DBG_DEFAULTS;109109+110110+/* Protect against concurrent firmware loading and parsing */111111+static struct mutex fw_mutex;112112+113113+static struct fwentry firmwares[] = {114114+ [0] = { "" },115115+ [BOARD_503_ISL3861] = { "atmel_at76c503-i3861.bin" },116116+ [BOARD_503_ISL3863] = { "atmel_at76c503-i3863.bin" },117117+ [BOARD_503] = { "atmel_at76c503-rfmd.bin" },118118+ [BOARD_503_ACC] = { "atmel_at76c503-rfmd-acc.bin" },119119+ [BOARD_505] = { "atmel_at76c505-rfmd.bin" },120120+ [BOARD_505_2958] = { "atmel_at76c505-rfmd2958.bin" },121121+ [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" },122122+ [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" },123123+};124124+125125+#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)126126+127127+static struct usb_device_id dev_table[] = {128128+ /*129129+ * at76c503-i3861130130+ */131131+ /* Generic AT76C503/3861 device */132132+ { USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861) },133133+ /* Linksys WUSB11 v2.1/v2.6 */134134+ { USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861) },135135+ /* Netgear MA101 rev. A */136136+ { USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861) },137137+ /* Tekram U300C / Allnet ALL0193 */138138+ { USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861) },139139+ /* HP HN210W J7801A */140140+ { USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861) },141141+ /* Sitecom/Z-Com/Zyxel M4Y-750 */142142+ { USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },143143+ /* Dynalink/Askey WLL013 (intersil) */144144+ { USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },145145+ /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */146146+ { USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },147147+ /* BenQ AWL300 */148148+ { USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },149149+ /* Addtron AWU-120, Compex WLU11 */150150+ { USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861) },151151+ /* Intel AP310 AnyPoint II USB */152152+ { USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861) },153153+ /* Dynalink L11U */154154+ { USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861) },155155+ /* Arescom WL-210, FCC id 07J-GL2411USB */156156+ { USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861) },157157+ /* I-O DATA WN-B11/USB */158158+ { USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861) },159159+ /* BT Voyager 1010 */160160+ { USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861) },161161+ /*162162+ * at76c503-i3863163163+ */164164+ /* Generic AT76C503/3863 device */165165+ { USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863) },166166+ /* Samsung SWL-2100U */167167+ { USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863) },168168+ /*169169+ * at76c503-rfmd170170+ */171171+ /* Generic AT76C503/RFMD device */172172+ { USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503) },173173+ /* Dynalink/Askey WLL013 (rfmd) */174174+ { USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503) },175175+ /* Linksys WUSB11 v2.6 */176176+ { USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503) },177177+ /* Network Everywhere NWU11B */178178+ { USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503) },179179+ /* Netgear MA101 rev. B */180180+ { USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503) },181181+ /* D-Link DWL-120 rev. E */182182+ { USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503) },183183+ /* Actiontec 802UAT1, HWU01150-01UK */184184+ { USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503) },185185+ /* AirVast W-Buddie WN210 */186186+ { USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503) },187187+ /* Dick Smith Electronics XH1153 802.11b USB adapter */188188+ { USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503) },189189+ /* CNet CNUSB611 */190190+ { USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503) },191191+ /* FiberLine FL-WL200U */192192+ { USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503) },193193+ /* BenQ AWL400 USB stick */194194+ { USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },195195+ /* 3Com 3CRSHEW696 */196196+ { USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },197197+ /* Siemens Santis ADSL WLAN USB adapter WLL 013 */198198+ { USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },199199+ /* Belkin F5D6050, version 2 */200200+ { USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },201201+ /* iBlitzz, BWU613 (not *B or *SB) */202202+ { USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503) },203203+ /* Gigabyte GN-WLBM101 */204204+ { USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503) },205205+ /* Planex GW-US11S */206206+ { USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503) },207207+ /* Internal WLAN adapter in h5[4,5]xx series iPAQs */208208+ { USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503) },209209+ /* Corega Wireless LAN USB-11 mini */210210+ { USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503) },211211+ /* Corega Wireless LAN USB-11 mini2 */212212+ { USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503) },213213+ /* Uniden PCW100 */214214+ { USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503) },215215+ /*216216+ * at76c503-rfmd-acc217217+ */218218+ /* SMC2664W */219219+ { USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC) },220220+ /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */221221+ { USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC) },222222+ /*223223+ * at76c505-rfmd224224+ */225225+ /* Generic AT76C505/RFMD */226226+ { USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505) },227227+ /*228228+ * at76c505-rfmd2958229229+ */230230+ /* Generic AT76C505/RFMD, OvisLink WL-1130USB */231231+ { USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },232232+ /* Fiberline FL-WL240U */233233+ { USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958) },234234+ /* CNet CNUSB-611G */235235+ { USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958) },236236+ /* Linksys WUSB11 v2.8 */237237+ { USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },238238+ /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */239239+ { USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },240240+ /* Corega WLAN USB Stick 11 */241241+ { USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },242242+ /* Microstar MSI Box MS6978 */243243+ { USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },244244+ /*245245+ * at76c505a-rfmd2958246246+ */247247+ /* Generic AT76C505A device */248248+ { USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A) },249249+ /* Generic AT76C505AS device */250250+ { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) },251251+ /* Siemens Gigaset USB WLAN Adapter 11 */252252+ { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) },253253+ /*254254+ * at76c505amx-rfmd255255+ */256256+ /* Generic AT76C505AMX device */257257+ { USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX) },258258+ { }259259+};260260+261261+MODULE_DEVICE_TABLE(usb, dev_table);262262+263263+/* Supported rates of this hardware, bit 7 marks basic rates */264264+static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 };265265+266266+static const char *const preambles[] = { "long", "short", "auto" };267267+268268+/* Firmware download */269269+/* DFU states */270270+#define STATE_IDLE 0x00271271+#define STATE_DETACH 0x01272272+#define STATE_DFU_IDLE 0x02273273+#define STATE_DFU_DOWNLOAD_SYNC 0x03274274+#define STATE_DFU_DOWNLOAD_BUSY 0x04275275+#define STATE_DFU_DOWNLOAD_IDLE 0x05276276+#define STATE_DFU_MANIFEST_SYNC 0x06277277+#define STATE_DFU_MANIFEST 0x07278278+#define STATE_DFU_MANIFEST_WAIT_RESET 0x08279279+#define STATE_DFU_UPLOAD_IDLE 0x09280280+#define STATE_DFU_ERROR 0x0a281281+282282+/* DFU commands */283283+#define DFU_DETACH 0284284+#define DFU_DNLOAD 1285285+#define DFU_UPLOAD 2286286+#define DFU_GETSTATUS 3287287+#define DFU_CLRSTATUS 4288288+#define DFU_GETSTATE 5289289+#define DFU_ABORT 6290290+291291+#define FW_BLOCK_SIZE 1024292292+293293+struct dfu_status {294294+ unsigned char status;295295+ unsigned char poll_timeout[3];296296+ unsigned char state;297297+ unsigned char string;298298+} __attribute__((packed));299299+300300+static inline int at76_is_intersil(enum board_type board)301301+{302302+ return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863);303303+}304304+305305+static inline int at76_is_503rfmd(enum board_type board)306306+{307307+ return (board == BOARD_503 || board == BOARD_503_ACC);308308+}309309+310310+static inline int at76_is_505a(enum board_type board)311311+{312312+ return (board == BOARD_505A || board == BOARD_505AMX);313313+}314314+315315+/* Load a block of the first (internal) part of the firmware */316316+static int at76_load_int_fw_block(struct usb_device *udev, int blockno,317317+ void *block, int size)318318+{319319+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD,320320+ USB_TYPE_CLASS | USB_DIR_OUT |321321+ USB_RECIP_INTERFACE, blockno, 0, block, size,322322+ USB_CTRL_GET_TIMEOUT);323323+}324324+325325+static int at76_dfu_get_status(struct usb_device *udev,326326+ struct dfu_status *status)327327+{328328+ int ret;329329+330330+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS,331331+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,332332+ 0, 0, status, sizeof(struct dfu_status),333333+ USB_CTRL_GET_TIMEOUT);334334+ return ret;335335+}336336+337337+static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)338338+{339339+ int ret;340340+341341+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE,342342+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,343343+ 0, 0, state, 1, USB_CTRL_GET_TIMEOUT);344344+ return ret;345345+}346346+347347+/* Convert timeout from the DFU status to jiffies */348348+static inline unsigned long at76_get_timeout(struct dfu_status *s)349349+{350350+ return msecs_to_jiffies((s->poll_timeout[2] << 16)351351+ | (s->poll_timeout[1] << 8)352352+ | (s->poll_timeout[0]));353353+}354354+355355+/* Load internal firmware from the buffer. If manifest_sync_timeout > 0, use356356+ * its value in jiffies in the MANIFEST_SYNC state. */357357+static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,358358+ int manifest_sync_timeout)359359+{360360+ u8 *block;361361+ struct dfu_status dfu_stat_buf;362362+ int ret = 0;363363+ int need_dfu_state = 1;364364+ int is_done = 0;365365+ u8 dfu_state = 0;366366+ u32 dfu_timeout = 0;367367+ int bsize = 0;368368+ int blockno = 0;369369+370370+ at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,371371+ manifest_sync_timeout);372372+373373+ if (!size) {374374+ dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");375375+ return -EINVAL;376376+ }377377+378378+ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);379379+ if (!block)380380+ return -ENOMEM;381381+382382+ do {383383+ if (need_dfu_state) {384384+ ret = at76_dfu_get_state(udev, &dfu_state);385385+ if (ret < 0) {386386+ dev_printk(KERN_ERR, &udev->dev,387387+ "cannot get DFU state: %d\n", ret);388388+ goto exit;389389+ }390390+ need_dfu_state = 0;391391+ }392392+393393+ switch (dfu_state) {394394+ case STATE_DFU_DOWNLOAD_SYNC:395395+ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");396396+ ret = at76_dfu_get_status(udev, &dfu_stat_buf);397397+ if (ret >= 0) {398398+ dfu_state = dfu_stat_buf.state;399399+ dfu_timeout = at76_get_timeout(&dfu_stat_buf);400400+ need_dfu_state = 0;401401+ } else402402+ dev_printk(KERN_ERR, &udev->dev,403403+ "at76_dfu_get_status returned %d\n",404404+ ret);405405+ break;406406+407407+ case STATE_DFU_DOWNLOAD_BUSY:408408+ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");409409+ need_dfu_state = 1;410410+411411+ at76_dbg(DBG_DFU, "DFU: Resetting device");412412+ schedule_timeout_interruptible(dfu_timeout);413413+ break;414414+415415+ case STATE_DFU_DOWNLOAD_IDLE:416416+ at76_dbg(DBG_DFU, "DOWNLOAD...");417417+ /* fall through */418418+ case STATE_DFU_IDLE:419419+ at76_dbg(DBG_DFU, "DFU IDLE");420420+421421+ bsize = min_t(int, size, FW_BLOCK_SIZE);422422+ memcpy(block, buf, bsize);423423+ at76_dbg(DBG_DFU, "int fw, size left = %5d, "424424+ "bsize = %4d, blockno = %2d", size, bsize,425425+ blockno);426426+ ret =427427+ at76_load_int_fw_block(udev, blockno, block, bsize);428428+ buf += bsize;429429+ size -= bsize;430430+ blockno++;431431+432432+ if (ret != bsize)433433+ dev_printk(KERN_ERR, &udev->dev,434434+ "at76_load_int_fw_block "435435+ "returned %d\n", ret);436436+ need_dfu_state = 1;437437+ break;438438+439439+ case STATE_DFU_MANIFEST_SYNC:440440+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");441441+442442+ ret = at76_dfu_get_status(udev, &dfu_stat_buf);443443+ if (ret < 0)444444+ break;445445+446446+ dfu_state = dfu_stat_buf.state;447447+ dfu_timeout = at76_get_timeout(&dfu_stat_buf);448448+ need_dfu_state = 0;449449+450450+ /* override the timeout from the status response,451451+ needed for AT76C505A */452452+ if (manifest_sync_timeout > 0)453453+ dfu_timeout = manifest_sync_timeout;454454+455455+ at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase");456456+ schedule_timeout_interruptible(dfu_timeout);457457+ break;458458+459459+ case STATE_DFU_MANIFEST:460460+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST");461461+ is_done = 1;462462+ break;463463+464464+ case STATE_DFU_MANIFEST_WAIT_RESET:465465+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");466466+ is_done = 1;467467+ break;468468+469469+ case STATE_DFU_UPLOAD_IDLE:470470+ at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");471471+ break;472472+473473+ case STATE_DFU_ERROR:474474+ at76_dbg(DBG_DFU, "STATE_DFU_ERROR");475475+ ret = -EPIPE;476476+ break;477477+478478+ default:479479+ at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);480480+ ret = -EINVAL;481481+ break;482482+ }483483+ } while (!is_done && (ret >= 0));484484+485485+exit:486486+ kfree(block);487487+ if (ret >= 0)488488+ ret = 0;489489+490490+ return ret;491491+}492492+493493+#define HEX2STR_BUFFERS 4494494+#define HEX2STR_MAX_LEN 64495495+#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)496496+497497+/* Convert binary data into hex string */498498+static char *hex2str(void *buf, int len)499499+{500500+ static atomic_t a = ATOMIC_INIT(0);501501+ static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];502502+ char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];503503+ char *obuf = ret;504504+ u8 *ibuf = buf;505505+506506+ if (len > HEX2STR_MAX_LEN)507507+ len = HEX2STR_MAX_LEN;508508+509509+ if (len <= 0) {510510+ ret[0] = '\0';511511+ return ret;512512+ }513513+514514+ while (len--) {515515+ *obuf++ = BIN2HEX(*ibuf >> 4);516516+ *obuf++ = BIN2HEX(*ibuf & 0xf);517517+ *obuf++ = '-';518518+ ibuf++;519519+ }520520+ *(--obuf) = '\0';521521+522522+ return ret;523523+}524524+525525+#define MAC2STR_BUFFERS 4526526+527527+static inline char *mac2str(u8 *mac)528528+{529529+ static atomic_t a = ATOMIC_INIT(0);530530+ static char bufs[MAC2STR_BUFFERS][6 * 3];531531+ char *str;532532+533533+ str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];534534+ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",535535+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);536536+ return str;537537+}538538+539539+/* LED trigger */540540+static int tx_activity;541541+static void at76_ledtrig_tx_timerfunc(unsigned long data);542542+static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);543543+DEFINE_LED_TRIGGER(ledtrig_tx);544544+545545+static void at76_ledtrig_tx_timerfunc(unsigned long data)546546+{547547+ static int tx_lastactivity;548548+549549+ if (tx_lastactivity != tx_activity) {550550+ tx_lastactivity = tx_activity;551551+ led_trigger_event(ledtrig_tx, LED_FULL);552552+ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);553553+ } else554554+ led_trigger_event(ledtrig_tx, LED_OFF);555555+}556556+557557+static void at76_ledtrig_tx_activity(void)558558+{559559+ tx_activity++;560560+ if (!timer_pending(&ledtrig_tx_timer))561561+ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);562562+}563563+564564+static int at76_remap(struct usb_device *udev)565565+{566566+ int ret;567567+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a,568568+ USB_TYPE_VENDOR | USB_DIR_OUT |569569+ USB_RECIP_INTERFACE, 0, 0, NULL, 0,570570+ USB_CTRL_GET_TIMEOUT);571571+ if (ret < 0)572572+ return ret;573573+ return 0;574574+}575575+576576+static int at76_get_op_mode(struct usb_device *udev)577577+{578578+ int ret;579579+ u8 saved;580580+ u8 *op_mode;581581+582582+ op_mode = kmalloc(1, GFP_NOIO);583583+ if (!op_mode)584584+ return -ENOMEM;585585+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,586586+ USB_TYPE_VENDOR | USB_DIR_IN |587587+ USB_RECIP_INTERFACE, 0x01, 0, op_mode, 1,588588+ USB_CTRL_GET_TIMEOUT);589589+ saved = *op_mode;590590+ kfree(op_mode);591591+592592+ if (ret < 0)593593+ return ret;594594+ else if (ret < 1)595595+ return -EIO;596596+ else597597+ return saved;598598+}599599+600600+/* Load a block of the second ("external") part of the firmware */601601+static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno,602602+ void *block, int size)603603+{604604+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,605605+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,606606+ 0x0802, blockno, block, size,607607+ USB_CTRL_GET_TIMEOUT);608608+}609609+610610+static inline int at76_get_hw_cfg(struct usb_device *udev,611611+ union at76_hwcfg *buf, int buf_size)612612+{613613+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,614614+ USB_TYPE_VENDOR | USB_DIR_IN |615615+ USB_RECIP_INTERFACE, 0x0a02, 0,616616+ buf, buf_size, USB_CTRL_GET_TIMEOUT);617617+}618618+619619+/* Intersil boards use a different "value" for GetHWConfig requests */620620+static inline int at76_get_hw_cfg_intersil(struct usb_device *udev,621621+ union at76_hwcfg *buf, int buf_size)622622+{623623+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,624624+ USB_TYPE_VENDOR | USB_DIR_IN |625625+ USB_RECIP_INTERFACE, 0x0902, 0,626626+ buf, buf_size, USB_CTRL_GET_TIMEOUT);627627+}628628+629629+/* Get the hardware configuration for the adapter and put it to the appropriate630630+ * fields of 'priv' (the GetHWConfig request and interpretation of the result631631+ * depends on the board type) */632632+static int at76_get_hw_config(struct at76_priv *priv)633633+{634634+ int ret;635635+ union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL);636636+637637+ if (!hwcfg)638638+ return -ENOMEM;639639+640640+ if (at76_is_intersil(priv->board_type)) {641641+ ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg,642642+ sizeof(hwcfg->i));643643+ if (ret < 0)644644+ goto exit;645645+ memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN);646646+ priv->regulatory_domain = hwcfg->i.regulatory_domain;647647+ } else if (at76_is_503rfmd(priv->board_type)) {648648+ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3));649649+ if (ret < 0)650650+ goto exit;651651+ memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN);652652+ priv->regulatory_domain = hwcfg->r3.regulatory_domain;653653+ } else {654654+ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5));655655+ if (ret < 0)656656+ goto exit;657657+ memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN);658658+ priv->regulatory_domain = hwcfg->r5.regulatory_domain;659659+ }660660+661661+exit:662662+ kfree(hwcfg);663663+ if (ret < 0)664664+ printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",665665+ wiphy_name(priv->hw->wiphy), ret);666666+667667+ return ret;668668+}669669+670670+static struct reg_domain const *at76_get_reg_domain(u16 code)671671+{672672+ int i;673673+ static struct reg_domain const fd_tab[] = {674674+ { 0x10, "FCC (USA)", 0x7ff }, /* ch 1-11 */675675+ { 0x20, "IC (Canada)", 0x7ff }, /* ch 1-11 */676676+ { 0x30, "ETSI (most of Europe)", 0x1fff }, /* ch 1-13 */677677+ { 0x31, "Spain", 0x600 }, /* ch 10-11 */678678+ { 0x32, "France", 0x1e00 }, /* ch 10-13 */679679+ { 0x40, "MKK (Japan)", 0x2000 }, /* ch 14 */680680+ { 0x41, "MKK1 (Japan)", 0x3fff }, /* ch 1-14 */681681+ { 0x50, "Israel", 0x3fc }, /* ch 3-9 */682682+ { 0x00, "<unknown>", 0xffffffff } /* ch 1-32 */683683+ };684684+685685+ /* Last entry is fallback for unknown domain code */686686+ for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++)687687+ if (code == fd_tab[i].code)688688+ break;689689+690690+ return &fd_tab[i];691691+}692692+693693+static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,694694+ int buf_size)695695+{696696+ int ret;697697+698698+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,699699+ USB_TYPE_VENDOR | USB_DIR_IN |700700+ USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size,701701+ USB_CTRL_GET_TIMEOUT);702702+ if (ret >= 0 && ret != buf_size)703703+ return -EIO;704704+ return ret;705705+}706706+707707+/* Return positive number for status, negative for an error */708708+static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)709709+{710710+ u8 *stat_buf;711711+ int ret;712712+713713+ stat_buf = kmalloc(40, GFP_NOIO);714714+ if (!stat_buf)715715+ return -ENOMEM;716716+717717+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22,718718+ USB_TYPE_VENDOR | USB_DIR_IN |719719+ USB_RECIP_INTERFACE, cmd, 0, stat_buf,720720+ 40, USB_CTRL_GET_TIMEOUT);721721+ if (ret >= 0)722722+ ret = stat_buf[5];723723+ kfree(stat_buf);724724+725725+ return ret;726726+}727727+728728+#define MAKE_CMD_CASE(c) case (c): return #c729729+static const char *at76_get_cmd_string(u8 cmd_status)730730+{731731+ switch (cmd_status) {732732+ MAKE_CMD_CASE(CMD_SET_MIB);733733+ MAKE_CMD_CASE(CMD_GET_MIB);734734+ MAKE_CMD_CASE(CMD_SCAN);735735+ MAKE_CMD_CASE(CMD_JOIN);736736+ MAKE_CMD_CASE(CMD_START_IBSS);737737+ MAKE_CMD_CASE(CMD_RADIO_ON);738738+ MAKE_CMD_CASE(CMD_RADIO_OFF);739739+ MAKE_CMD_CASE(CMD_STARTUP);740740+ }741741+742742+ return "UNKNOWN";743743+}744744+745745+static int at76_set_card_command(struct usb_device *udev, u8 cmd, void *buf,746746+ int buf_size)747747+{748748+ int ret;749749+ struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) +750750+ buf_size, GFP_KERNEL);751751+752752+ if (!cmd_buf)753753+ return -ENOMEM;754754+755755+ cmd_buf->cmd = cmd;756756+ cmd_buf->reserved = 0;757757+ cmd_buf->size = cpu_to_le16(buf_size);758758+ memcpy(cmd_buf->data, buf, buf_size);759759+760760+ at76_dbg_dump(DBG_CMD, cmd_buf, sizeof(struct at76_command) + buf_size,761761+ "issuing command %s (0x%02x)",762762+ at76_get_cmd_string(cmd), cmd);763763+764764+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,765765+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,766766+ 0, 0, cmd_buf,767767+ sizeof(struct at76_command) + buf_size,768768+ USB_CTRL_GET_TIMEOUT);769769+ kfree(cmd_buf);770770+ return ret;771771+}772772+773773+#define MAKE_CMD_STATUS_CASE(c) case (c): return #c774774+static const char *at76_get_cmd_status_string(u8 cmd_status)775775+{776776+ switch (cmd_status) {777777+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE);778778+ MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE);779779+ MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN);780780+ MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER);781781+ MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED);782782+ MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT);783783+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS);784784+ MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE);785785+ MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED);786786+ }787787+788788+ return "UNKNOWN";789789+}790790+791791+/* Wait until the command is completed */792792+static int at76_wait_completion(struct at76_priv *priv, int cmd)793793+{794794+ int status = 0;795795+ unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT;796796+797797+ do {798798+ status = at76_get_cmd_status(priv->udev, cmd);799799+ if (status < 0) {800800+ printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",801801+ wiphy_name(priv->hw->wiphy), status);802802+ break;803803+ }804804+805805+ at76_dbg(DBG_WAIT_COMPLETE,806806+ "%s: Waiting on cmd %d, status = %d (%s)",807807+ wiphy_name(priv->hw->wiphy), cmd, status,808808+ at76_get_cmd_status_string(status));809809+810810+ if (status != CMD_STATUS_IN_PROGRESS811811+ && status != CMD_STATUS_IDLE)812812+ break;813813+814814+ schedule_timeout_interruptible(HZ / 10); /* 100 ms */815815+ if (time_after(jiffies, timeout)) {816816+ printk(KERN_ERR817817+ "%s: completion timeout for command %d\n",818818+ wiphy_name(priv->hw->wiphy), cmd);819819+ status = -ETIMEDOUT;820820+ break;821821+ }822822+ } while (1);823823+824824+ return status;825825+}826826+827827+static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf)828828+{829829+ int ret;830830+831831+ ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf,832832+ offsetof(struct set_mib_buffer,833833+ data) + buf->size);834834+ if (ret < 0)835835+ return ret;836836+837837+ ret = at76_wait_completion(priv, CMD_SET_MIB);838838+ if (ret != CMD_STATUS_COMPLETE) {839839+ printk(KERN_INFO840840+ "%s: set_mib: at76_wait_completion failed "841841+ "with %d\n", wiphy_name(priv->hw->wiphy), ret);842842+ ret = -EIO;843843+ }844844+845845+ return ret;846846+}847847+848848+/* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */849849+static int at76_set_radio(struct at76_priv *priv, int enable)850850+{851851+ int ret;852852+ int cmd;853853+854854+ if (priv->radio_on == enable)855855+ return 0;856856+857857+ cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF;858858+859859+ ret = at76_set_card_command(priv->udev, cmd, NULL, 0);860860+ if (ret < 0)861861+ printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",862862+ wiphy_name(priv->hw->wiphy), cmd, ret);863863+ else864864+ ret = 1;865865+866866+ priv->radio_on = enable;867867+ return ret;868868+}869869+870870+/* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */871871+static int at76_set_pm_mode(struct at76_priv *priv)872872+{873873+ int ret = 0;874874+875875+ priv->mib_buf.type = MIB_MAC_MGMT;876876+ priv->mib_buf.size = 1;877877+ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode);878878+ priv->mib_buf.data.byte = priv->pm_mode;879879+880880+ ret = at76_set_mib(priv, &priv->mib_buf);881881+ if (ret < 0)882882+ printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",883883+ wiphy_name(priv->hw->wiphy), ret);884884+885885+ return ret;886886+}887887+888888+static int at76_set_preamble(struct at76_priv *priv, u8 type)889889+{890890+ int ret = 0;891891+892892+ priv->mib_buf.type = MIB_LOCAL;893893+ priv->mib_buf.size = 1;894894+ priv->mib_buf.index = offsetof(struct mib_local, preamble_type);895895+ priv->mib_buf.data.byte = type;896896+897897+ ret = at76_set_mib(priv, &priv->mib_buf);898898+ if (ret < 0)899899+ printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",900900+ wiphy_name(priv->hw->wiphy), ret);901901+902902+ return ret;903903+}904904+905905+static int at76_set_frag(struct at76_priv *priv, u16 size)906906+{907907+ int ret = 0;908908+909909+ priv->mib_buf.type = MIB_MAC;910910+ priv->mib_buf.size = 2;911911+ priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold);912912+ priv->mib_buf.data.word = cpu_to_le16(size);913913+914914+ ret = at76_set_mib(priv, &priv->mib_buf);915915+ if (ret < 0)916916+ printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",917917+ wiphy_name(priv->hw->wiphy), ret);918918+919919+ return ret;920920+}921921+922922+static int at76_set_rts(struct at76_priv *priv, u16 size)923923+{924924+ int ret = 0;925925+926926+ priv->mib_buf.type = MIB_MAC;927927+ priv->mib_buf.size = 2;928928+ priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold);929929+ priv->mib_buf.data.word = cpu_to_le16(size);930930+931931+ ret = at76_set_mib(priv, &priv->mib_buf);932932+ if (ret < 0)933933+ printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",934934+ wiphy_name(priv->hw->wiphy), ret);935935+936936+ return ret;937937+}938938+939939+static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff)940940+{941941+ int ret = 0;942942+943943+ priv->mib_buf.type = MIB_LOCAL;944944+ priv->mib_buf.size = 1;945945+ priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback);946946+ priv->mib_buf.data.byte = onoff;947947+948948+ ret = at76_set_mib(priv, &priv->mib_buf);949949+ if (ret < 0)950950+ printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",951951+ wiphy_name(priv->hw->wiphy), ret);952952+953953+ return ret;954954+}955955+956956+static void at76_dump_mib_mac_addr(struct at76_priv *priv)957957+{958958+ int i;959959+ int ret;960960+ struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr),961961+ GFP_KERNEL);962962+963963+ if (!m)964964+ return;965965+966966+ ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,967967+ sizeof(struct mib_mac_addr));968968+ if (ret < 0) {969969+ printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",970970+ wiphy_name(priv->hw->wiphy), ret);971971+ goto exit;972972+ }973973+974974+ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",975975+ wiphy_name(priv->hw->wiphy),976976+ mac2str(m->mac_addr), m->res[0], m->res[1]);977977+ for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)978978+ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "979979+ "status %d", wiphy_name(priv->hw->wiphy), i,980980+ mac2str(m->group_addr[i]), m->group_addr_status[i]);981981+exit:982982+ kfree(m);983983+}984984+985985+static void at76_dump_mib_mac_wep(struct at76_priv *priv)986986+{987987+ int i;988988+ int ret;989989+ int key_len;990990+ struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL);991991+992992+ if (!m)993993+ return;994994+995995+ ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,996996+ sizeof(struct mib_mac_wep));997997+ if (ret < 0) {998998+ printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",999999+ wiphy_name(priv->hw->wiphy), ret);10001000+ goto exit;10011001+ }10021002+10031003+ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u "10041004+ "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u "10051005+ "encr_level %u key %d", wiphy_name(priv->hw->wiphy),10061006+ m->privacy_invoked, m->wep_default_key_id,10071007+ m->wep_key_mapping_len, m->exclude_unencrypted,10081008+ le32_to_cpu(m->wep_icv_error_count),10091009+ le32_to_cpu(m->wep_excluded_count), m->encryption_level,10101010+ m->wep_default_key_id);10111011+10121012+ key_len = (m->encryption_level == 1) ?10131013+ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;10141014+10151015+ for (i = 0; i < WEP_KEYS; i++)10161016+ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",10171017+ wiphy_name(priv->hw->wiphy), i,10181018+ hex2str(m->wep_default_keyvalue[i], key_len));10191019+exit:10201020+ kfree(m);10211021+}10221022+10231023+static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)10241024+{10251025+ int ret;10261026+ struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt),10271027+ GFP_KERNEL);10281028+10291029+ if (!m)10301030+ return;10311031+10321032+ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,10331033+ sizeof(struct mib_mac_mgmt));10341034+ if (ret < 0) {10351035+ printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",10361036+ wiphy_name(priv->hw->wiphy), ret);10371037+ goto exit;10381038+ }10391039+10401040+ at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "10411041+ "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "10421042+ "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "10431043+ "current_bssid %s current_essid %s current_bss_type %d "10441044+ "pm_mode %d ibss_change %d res %d "10451045+ "multi_domain_capability_implemented %d "10461046+ "international_roaming %d country_string %.3s",10471047+ wiphy_name(priv->hw->wiphy), le16_to_cpu(m->beacon_period),10481048+ le16_to_cpu(m->CFP_max_duration),10491049+ le16_to_cpu(m->medium_occupancy_limit),10501050+ le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),10511051+ m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,10521052+ m->CFP_period, mac2str(m->current_bssid),10531053+ hex2str(m->current_essid, IW_ESSID_MAX_SIZE),10541054+ m->current_bss_type, m->power_mgmt_mode, m->ibss_change,10551055+ m->res, m->multi_domain_capability_implemented,10561056+ m->multi_domain_capability_enabled, m->country_string);10571057+exit:10581058+ kfree(m);10591059+}10601060+10611061+static void at76_dump_mib_mac(struct at76_priv *priv)10621062+{10631063+ int ret;10641064+ struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL);10651065+10661066+ if (!m)10671067+ return;10681068+10691069+ ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));10701070+ if (ret < 0) {10711071+ printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",10721072+ wiphy_name(priv->hw->wiphy), ret);10731073+ goto exit;10741074+ }10751075+10761076+ at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d "10771077+ "max_rx_lifetime %d frag_threshold %d rts_threshold %d "10781078+ "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "10791079+ "scan_type %d scan_channel %d probe_delay %u "10801080+ "min_channel_time %d max_channel_time %d listen_int %d "10811081+ "desired_ssid %s desired_bssid %s desired_bsstype %d",10821082+ wiphy_name(priv->hw->wiphy),10831083+ le32_to_cpu(m->max_tx_msdu_lifetime),10841084+ le32_to_cpu(m->max_rx_lifetime),10851085+ le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold),10861086+ le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax),10871087+ m->short_retry_time, m->long_retry_time, m->scan_type,10881088+ m->scan_channel, le16_to_cpu(m->probe_delay),10891089+ le16_to_cpu(m->min_channel_time),10901090+ le16_to_cpu(m->max_channel_time),10911091+ le16_to_cpu(m->listen_interval),10921092+ hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),10931093+ mac2str(m->desired_bssid), m->desired_bsstype);10941094+exit:10951095+ kfree(m);10961096+}10971097+10981098+static void at76_dump_mib_phy(struct at76_priv *priv)10991099+{11001100+ int ret;11011101+ struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);11021102+11031103+ if (!m)11041104+ return;11051105+11061106+ ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));11071107+ if (ret < 0) {11081108+ printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",11091109+ wiphy_name(priv->hw->wiphy), ret);11101110+ goto exit;11111111+ }11121112+11131113+ at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d "11141114+ "sifs_time %d preamble_length %d plcp_header_length %d "11151115+ "mpdu_max_length %d cca_mode_supported %d operation_rate_set "11161116+ "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d "11171117+ "phy_type %d current_reg_domain %d",11181118+ wiphy_name(priv->hw->wiphy), le32_to_cpu(m->ed_threshold),11191119+ le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time),11201120+ le16_to_cpu(m->preamble_length),11211121+ le16_to_cpu(m->plcp_header_length),11221122+ le16_to_cpu(m->mpdu_max_length),11231123+ le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0],11241124+ m->operation_rate_set[1], m->operation_rate_set[2],11251125+ m->operation_rate_set[3], m->channel_id, m->current_cca_mode,11261126+ m->phy_type, m->current_reg_domain);11271127+exit:11281128+ kfree(m);11291129+}11301130+11311131+static void at76_dump_mib_local(struct at76_priv *priv)11321132+{11331133+ int ret;11341134+ struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);11351135+11361136+ if (!m)11371137+ return;11381138+11391139+ ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));11401140+ if (ret < 0) {11411141+ printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",11421142+ wiphy_name(priv->hw->wiphy), ret);11431143+ goto exit;11441144+ }11451145+11461146+ at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d "11471147+ "txautorate_fallback %d ssid_size %d promiscuous_mode %d "11481148+ "preamble_type %d", wiphy_name(priv->hw->wiphy),11491149+ m->beacon_enable,11501150+ m->txautorate_fallback, m->ssid_size, m->promiscuous_mode,11511151+ m->preamble_type);11521152+exit:11531153+ kfree(m);11541154+}11551155+11561156+static void at76_dump_mib_mdomain(struct at76_priv *priv)11571157+{11581158+ int ret;11591159+ struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL);11601160+11611161+ if (!m)11621162+ return;11631163+11641164+ ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,11651165+ sizeof(struct mib_mdomain));11661166+ if (ret < 0) {11671167+ printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",11681168+ wiphy_name(priv->hw->wiphy), ret);11691169+ goto exit;11701170+ }11711171+11721172+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",11731173+ wiphy_name(priv->hw->wiphy),11741174+ hex2str(m->channel_list, sizeof(m->channel_list)));11751175+11761176+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",11771177+ wiphy_name(priv->hw->wiphy),11781178+ hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));11791179+exit:11801180+ kfree(m);11811181+}11821182+11831183+/* Enable monitor mode */11841184+static int at76_start_monitor(struct at76_priv *priv)11851185+{11861186+ struct at76_req_scan scan;11871187+ int ret;11881188+11891189+ memset(&scan, 0, sizeof(struct at76_req_scan));11901190+ memset(scan.bssid, 0xff, ETH_ALEN);11911191+11921192+ scan.channel = priv->channel;11931193+ scan.scan_type = SCAN_TYPE_PASSIVE;11941194+ scan.international_scan = 0;11951195+11961196+ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));11971197+ if (ret >= 0)11981198+ ret = at76_get_cmd_status(priv->udev, CMD_SCAN);11991199+12001200+ return ret;12011201+}12021202+12031203+/* Calculate padding from txbuf->wlength (which excludes the USB TX header),12041204+ likely to compensate a flaw in the AT76C503A USB part ... */12051205+static inline int at76_calc_padding(int wlen)12061206+{12071207+ /* add the USB TX header */12081208+ wlen += AT76_TX_HDRLEN;12091209+12101210+ wlen = wlen % 64;12111211+12121212+ if (wlen < 50)12131213+ return 50 - wlen;12141214+12151215+ if (wlen >= 61)12161216+ return 64 + 50 - wlen;12171217+12181218+ return 0;12191219+}12201220+12211221+static void at76_rx_callback(struct urb *urb)12221222+{12231223+ struct at76_priv *priv = urb->context;12241224+12251225+ priv->rx_tasklet.data = (unsigned long)urb;12261226+ tasklet_schedule(&priv->rx_tasklet);12271227+ return;12281228+}12291229+12301230+static int at76_submit_rx_urb(struct at76_priv *priv)12311231+{12321232+ int ret;12331233+ int size;12341234+ struct sk_buff *skb = priv->rx_skb;12351235+12361236+ if (!priv->rx_urb) {12371237+ printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",12381238+ wiphy_name(priv->hw->wiphy), __func__);12391239+ return -EFAULT;12401240+ }12411241+12421242+ if (!skb) {12431243+ skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));12441244+ if (!skb) {12451245+ printk(KERN_ERR "%s: cannot allocate rx skbuff\n",12461246+ wiphy_name(priv->hw->wiphy));12471247+ ret = -ENOMEM;12481248+ goto exit;12491249+ }12501250+ priv->rx_skb = skb;12511251+ } else {12521252+ skb_push(skb, skb_headroom(skb));12531253+ skb_trim(skb, 0);12541254+ }12551255+12561256+ size = skb_tailroom(skb);12571257+ usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe,12581258+ skb_put(skb, size), size, at76_rx_callback, priv);12591259+ ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC);12601260+ if (ret < 0) {12611261+ if (ret == -ENODEV)12621262+ at76_dbg(DBG_DEVSTART,12631263+ "usb_submit_urb returned -ENODEV");12641264+ else12651265+ printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",12661266+ wiphy_name(priv->hw->wiphy), ret);12671267+ }12681268+12691269+exit:12701270+ if (ret < 0 && ret != -ENODEV)12711271+ printk(KERN_ERR "%s: cannot submit rx urb - please unload the "12721272+ "driver and/or power cycle the device\n",12731273+ wiphy_name(priv->hw->wiphy));12741274+12751275+ return ret;12761276+}12771277+12781278+/* Download external firmware */12791279+static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)12801280+{12811281+ int ret;12821282+ int op_mode;12831283+ int blockno = 0;12841284+ int bsize;12851285+ u8 *block;12861286+ u8 *buf = fwe->extfw;12871287+ int size = fwe->extfw_size;12881288+12891289+ if (!buf || !size)12901290+ return -ENOENT;12911291+12921292+ op_mode = at76_get_op_mode(udev);12931293+ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);12941294+12951295+ if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {12961296+ dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",12971297+ op_mode);12981298+ return -EINVAL;12991299+ }13001300+13011301+ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);13021302+ if (!block)13031303+ return -ENOMEM;13041304+13051305+ at76_dbg(DBG_DEVSTART, "downloading external firmware");13061306+13071307+ /* for fw >= 0.100, the device needs an extra empty block */13081308+ do {13091309+ bsize = min_t(int, size, FW_BLOCK_SIZE);13101310+ memcpy(block, buf, bsize);13111311+ at76_dbg(DBG_DEVSTART,13121312+ "ext fw, size left = %5d, bsize = %4d, blockno = %2d",13131313+ size, bsize, blockno);13141314+ ret = at76_load_ext_fw_block(udev, blockno, block, bsize);13151315+ if (ret != bsize) {13161316+ dev_printk(KERN_ERR, &udev->dev,13171317+ "loading %dth firmware block failed: %d\n",13181318+ blockno, ret);13191319+ goto exit;13201320+ }13211321+ buf += bsize;13221322+ size -= bsize;13231323+ blockno++;13241324+ } while (bsize > 0);13251325+13261326+ if (at76_is_505a(fwe->board_type)) {13271327+ at76_dbg(DBG_DEVSTART, "200 ms delay for 505a");13281328+ schedule_timeout_interruptible(HZ / 5 + 1);13291329+ }13301330+13311331+exit:13321332+ kfree(block);13331333+ if (ret < 0)13341334+ dev_printk(KERN_ERR, &udev->dev,13351335+ "downloading external firmware failed: %d\n", ret);13361336+ return ret;13371337+}13381338+13391339+/* Download internal firmware */13401340+static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)13411341+{13421342+ int ret;13431343+ int need_remap = !at76_is_505a(fwe->board_type);13441344+13451345+ ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size,13461346+ need_remap ? 0 : 2 * HZ);13471347+13481348+ if (ret < 0) {13491349+ dev_printk(KERN_ERR, &udev->dev,13501350+ "downloading internal fw failed with %d\n", ret);13511351+ goto exit;13521352+ }13531353+13541354+ at76_dbg(DBG_DEVSTART, "sending REMAP");13551355+13561356+ /* no REMAP for 505A (see SF driver) */13571357+ if (need_remap) {13581358+ ret = at76_remap(udev);13591359+ if (ret < 0) {13601360+ dev_printk(KERN_ERR, &udev->dev,13611361+ "sending REMAP failed with %d\n", ret);13621362+ goto exit;13631363+ }13641364+ }13651365+13661366+ at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds");13671367+ schedule_timeout_interruptible(2 * HZ + 1);13681368+ usb_reset_device(udev);13691369+13701370+exit:13711371+ return ret;13721372+}13731373+13741374+static int at76_startup_device(struct at76_priv *priv)13751375+{13761376+ struct at76_card_config *ccfg = &priv->card_config;13771377+ int ret;13781378+13791379+ at76_dbg(DBG_PARAMS,13801380+ "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "13811381+ "keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size,13821382+ priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE),13831383+ priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",13841384+ priv->channel, priv->wep_enabled ? "enabled" : "disabled",13851385+ priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);13861386+ at76_dbg(DBG_PARAMS,13871387+ "%s param: preamble %s rts %d retry %d frag %d "13881388+ "txrate %s auth_mode %d", wiphy_name(priv->hw->wiphy),13891389+ preambles[priv->preamble_type], priv->rts_threshold,13901390+ priv->short_retry_limit, priv->frag_threshold,13911391+ priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate ==13921392+ TX_RATE_2MBIT ? "2MBit" : priv->txrate ==13931393+ TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate ==13941394+ TX_RATE_11MBIT ? "11MBit" : priv->txrate ==13951395+ TX_RATE_AUTO ? "auto" : "<invalid>", priv->auth_mode);13961396+ at76_dbg(DBG_PARAMS,13971397+ "%s param: pm_mode %d pm_period %d auth_mode %s "13981398+ "scan_times %d %d scan_mode %s",13991399+ wiphy_name(priv->hw->wiphy), priv->pm_mode, priv->pm_period,14001400+ priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret",14011401+ priv->scan_min_time, priv->scan_max_time,14021402+ priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive");14031403+14041404+ memset(ccfg, 0, sizeof(struct at76_card_config));14051405+ ccfg->promiscuous_mode = 0;14061406+ ccfg->short_retry_limit = priv->short_retry_limit;14071407+14081408+ if (priv->wep_enabled) {14091409+ if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)14101410+ ccfg->encryption_type = 2;14111411+ else14121412+ ccfg->encryption_type = 1;14131413+14141414+ /* jal: always exclude unencrypted if WEP is active */14151415+ ccfg->exclude_unencrypted = 1;14161416+ } else {14171417+ ccfg->exclude_unencrypted = 0;14181418+ ccfg->encryption_type = 0;14191419+ }14201420+14211421+ ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold);14221422+ ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold);14231423+14241424+ memcpy(ccfg->basic_rate_set, hw_rates, 4);14251425+ /* jal: really needed, we do a set_mib for autorate later ??? */14261426+ ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0);14271427+ ccfg->channel = priv->channel;14281428+ ccfg->privacy_invoked = priv->wep_enabled;14291429+ memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE);14301430+ ccfg->ssid_len = priv->essid_size;14311431+14321432+ ccfg->wep_default_key_id = priv->wep_key_id;14331433+ memcpy(ccfg->wep_default_key_value, priv->wep_keys,14341434+ sizeof(priv->wep_keys));14351435+14361436+ ccfg->short_preamble = priv->preamble_type;14371437+ ccfg->beacon_period = cpu_to_le16(priv->beacon_period);14381438+14391439+ ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,14401440+ sizeof(struct at76_card_config));14411441+ if (ret < 0) {14421442+ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",14431443+ wiphy_name(priv->hw->wiphy), ret);14441444+ return ret;14451445+ }14461446+14471447+ at76_wait_completion(priv, CMD_STARTUP);14481448+14491449+ /* remove BSSID from previous run */14501450+ memset(priv->bssid, 0, ETH_ALEN);14511451+14521452+ if (at76_set_radio(priv, 1) == 1)14531453+ at76_wait_completion(priv, CMD_RADIO_ON);14541454+14551455+ ret = at76_set_preamble(priv, priv->preamble_type);14561456+ if (ret < 0)14571457+ return ret;14581458+14591459+ ret = at76_set_frag(priv, priv->frag_threshold);14601460+ if (ret < 0)14611461+ return ret;14621462+14631463+ ret = at76_set_rts(priv, priv->rts_threshold);14641464+ if (ret < 0)14651465+ return ret;14661466+14671467+ ret = at76_set_autorate_fallback(priv,14681468+ priv->txrate == TX_RATE_AUTO ? 1 : 0);14691469+ if (ret < 0)14701470+ return ret;14711471+14721472+ ret = at76_set_pm_mode(priv);14731473+ if (ret < 0)14741474+ return ret;14751475+14761476+ if (at76_debug & DBG_MIB) {14771477+ at76_dump_mib_mac(priv);14781478+ at76_dump_mib_mac_addr(priv);14791479+ at76_dump_mib_mac_mgmt(priv);14801480+ at76_dump_mib_mac_wep(priv);14811481+ at76_dump_mib_mdomain(priv);14821482+ at76_dump_mib_phy(priv);14831483+ at76_dump_mib_local(priv);14841484+ }14851485+14861486+ return 0;14871487+}14881488+14891489+/* Enable or disable promiscuous mode */14901490+static void at76_work_set_promisc(struct work_struct *work)14911491+{14921492+ struct at76_priv *priv = container_of(work, struct at76_priv,14931493+ work_set_promisc);14941494+ int ret = 0;14951495+14961496+ if (priv->device_unplugged)14971497+ return;14981498+14991499+ mutex_lock(&priv->mtx);15001500+15011501+ priv->mib_buf.type = MIB_LOCAL;15021502+ priv->mib_buf.size = 1;15031503+ priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode);15041504+ priv->mib_buf.data.byte = priv->promisc ? 1 : 0;15051505+15061506+ ret = at76_set_mib(priv, &priv->mib_buf);15071507+ if (ret < 0)15081508+ printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",15091509+ wiphy_name(priv->hw->wiphy), ret);15101510+15111511+ mutex_unlock(&priv->mtx);15121512+}15131513+15141514+/* Submit Rx urb back to the device */15151515+static void at76_work_submit_rx(struct work_struct *work)15161516+{15171517+ struct at76_priv *priv = container_of(work, struct at76_priv,15181518+ work_submit_rx);15191519+15201520+ mutex_lock(&priv->mtx);15211521+ at76_submit_rx_urb(priv);15221522+ mutex_unlock(&priv->mtx);15231523+}15241524+15251525+static void at76_rx_tasklet(unsigned long param)15261526+{15271527+ struct urb *urb = (struct urb *)param;15281528+ struct at76_priv *priv = urb->context;15291529+ struct at76_rx_buffer *buf;15301530+ struct ieee80211_rx_status rx_status = { 0 };15311531+15321532+ if (priv->device_unplugged) {15331533+ at76_dbg(DBG_DEVSTART, "device unplugged");15341534+ if (urb)15351535+ at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);15361536+ return;15371537+ }15381538+15391539+ if (!priv->rx_skb || !priv->rx_skb->data)15401540+ return;15411541+15421542+ buf = (struct at76_rx_buffer *)priv->rx_skb->data;15431543+15441544+ if (urb->status != 0) {15451545+ if (urb->status != -ENOENT && urb->status != -ECONNRESET)15461546+ at76_dbg(DBG_URB,15471547+ "%s %s: - nonzero Rx bulk status received: %d",15481548+ __func__, wiphy_name(priv->hw->wiphy),15491549+ urb->status);15501550+ return;15511551+ }15521552+15531553+ at76_dbg(DBG_RX_ATMEL_HDR,15541554+ "%s: rx frame: rate %d rssi %d noise %d link %d",15551555+ wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi,15561556+ buf->noise_level, buf->link_quality);15571557+15581558+ skb_pull(priv->rx_skb, AT76_RX_HDRLEN);15591559+ skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength));15601560+ at76_dbg_dump(DBG_RX_DATA, priv->rx_skb->data,15611561+ priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len);15621562+15631563+ rx_status.signal = buf->rssi;15641564+ rx_status.flag |= RX_FLAG_DECRYPTED;15651565+ rx_status.flag |= RX_FLAG_IV_STRIPPED;15661566+15671567+ at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",15681568+ priv->rx_skb->len, priv->rx_skb->data_len);15691569+ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);15701570+15711571+ /* Use a new skb for the next receive */15721572+ priv->rx_skb = NULL;15731573+15741574+ at76_submit_rx_urb(priv);15751575+}15761576+15771577+/* Load firmware into kernel memory and parse it */15781578+static struct fwentry *at76_load_firmware(struct usb_device *udev,15791579+ enum board_type board_type)15801580+{15811581+ int ret;15821582+ char *str;15831583+ struct at76_fw_header *fwh;15841584+ struct fwentry *fwe = &firmwares[board_type];15851585+15861586+ mutex_lock(&fw_mutex);15871587+15881588+ if (fwe->loaded) {15891589+ at76_dbg(DBG_FW, "re-using previously loaded fw");15901590+ goto exit;15911591+ }15921592+15931593+ at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);15941594+ ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);15951595+ if (ret < 0) {15961596+ dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",15971597+ fwe->fwname);15981598+ dev_printk(KERN_ERR, &udev->dev,15991599+ "you may need to download the firmware from "16001600+ "http://developer.berlios.de/projects/at76c503a/\n");16011601+ goto exit;16021602+ }16031603+16041604+ at76_dbg(DBG_FW, "got it.");16051605+ fwh = (struct at76_fw_header *)(fwe->fw->data);16061606+16071607+ if (fwe->fw->size <= sizeof(*fwh)) {16081608+ dev_printk(KERN_ERR, &udev->dev,16091609+ "firmware is too short (0x%zx)\n", fwe->fw->size);16101610+ goto exit;16111611+ }16121612+16131613+ /* CRC currently not checked */16141614+ fwe->board_type = le32_to_cpu(fwh->board_type);16151615+ if (fwe->board_type != board_type) {16161616+ dev_printk(KERN_ERR, &udev->dev,16171617+ "board type mismatch, requested %u, got %u\n",16181618+ board_type, fwe->board_type);16191619+ goto exit;16201620+ }16211621+16221622+ fwe->fw_version.major = fwh->major;16231623+ fwe->fw_version.minor = fwh->minor;16241624+ fwe->fw_version.patch = fwh->patch;16251625+ fwe->fw_version.build = fwh->build;16261626+16271627+ str = (char *)fwh + le32_to_cpu(fwh->str_offset);16281628+ fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset);16291629+ fwe->intfw_size = le32_to_cpu(fwh->int_fw_len);16301630+ fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset);16311631+ fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len);16321632+16331633+ fwe->loaded = 1;16341634+16351635+ dev_printk(KERN_DEBUG, &udev->dev,16361636+ "using firmware %s (version %d.%d.%d-%d)\n",16371637+ fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build);16381638+16391639+ at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type,16401640+ le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len),16411641+ le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len));16421642+ at76_dbg(DBG_DEVSTART, "firmware id %s", str);16431643+16441644+exit:16451645+ mutex_unlock(&fw_mutex);16461646+16471647+ if (fwe->loaded)16481648+ return fwe;16491649+ else16501650+ return NULL;16511651+}16521652+16531653+static void at76_mac80211_tx_callback(struct urb *urb)16541654+{16551655+ struct at76_priv *priv = urb->context;16561656+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);16571657+16581658+ at76_dbg(DBG_MAC80211, "%s()", __func__);16591659+16601660+ switch (urb->status) {16611661+ case 0:16621662+ /* success */16631663+ info->flags |= IEEE80211_TX_STAT_ACK;16641664+ break;16651665+ case -ENOENT:16661666+ case -ECONNRESET:16671667+ /* fail, urb has been unlinked */16681668+ /* FIXME: add error message */16691669+ break;16701670+ default:16711671+ at76_dbg(DBG_URB, "%s - nonzero tx status received: %d",16721672+ __func__, urb->status);16731673+ break;16741674+ }16751675+16761676+ memset(&info->status, 0, sizeof(info->status));16771677+16781678+ ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);16791679+16801680+ priv->tx_skb = NULL;16811681+16821682+ ieee80211_wake_queues(priv->hw);16831683+}16841684+16851685+static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)16861686+{16871687+ struct at76_priv *priv = hw->priv;16881688+ struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;16891689+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);16901690+ int padding, submit_len, ret;16911691+16921692+ at76_dbg(DBG_MAC80211, "%s()", __func__);16931693+16941694+ if (priv->tx_urb->status == -EINPROGRESS) {16951695+ printk(KERN_ERR "%s: %s called while tx urb is pending\n",16961696+ wiphy_name(priv->hw->wiphy), __func__);16971697+ return NETDEV_TX_BUSY;16981698+ }16991699+17001700+ ieee80211_stop_queues(hw);17011701+17021702+ at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */17031703+17041704+ WARN_ON(priv->tx_skb != NULL);17051705+17061706+ priv->tx_skb = skb;17071707+ padding = at76_calc_padding(skb->len);17081708+ submit_len = AT76_TX_HDRLEN + skb->len + padding;17091709+17101710+ /* setup 'Atmel' header */17111711+ memset(tx_buffer, 0, sizeof(*tx_buffer));17121712+ tx_buffer->padding = padding;17131713+ tx_buffer->wlength = cpu_to_le16(skb->len);17141714+ tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, info)->hw_value;17151715+ memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved));17161716+ memcpy(tx_buffer->packet, skb->data, skb->len);17171717+17181718+ at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr",17191719+ wiphy_name(priv->hw->wiphy), le16_to_cpu(tx_buffer->wlength),17201720+ tx_buffer->padding, tx_buffer->tx_rate);17211721+17221722+ /* send stuff */17231723+ at76_dbg_dump(DBG_TX_DATA_CONTENT, tx_buffer, submit_len,17241724+ "%s(): tx_buffer %d bytes:", __func__, submit_len);17251725+ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer,17261726+ submit_len, at76_mac80211_tx_callback, priv);17271727+ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);17281728+ if (ret) {17291729+ printk(KERN_ERR "%s: error in tx submit urb: %d\n",17301730+ wiphy_name(priv->hw->wiphy), ret);17311731+ if (ret == -EINVAL)17321732+ printk(KERN_ERR17331733+ "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",17341734+ wiphy_name(priv->hw->wiphy), priv->tx_urb,17351735+ priv->tx_urb->hcpriv, priv->tx_urb->complete);17361736+ }17371737+17381738+ return 0;17391739+}17401740+17411741+static int at76_mac80211_start(struct ieee80211_hw *hw)17421742+{17431743+ struct at76_priv *priv = hw->priv;17441744+ int ret;17451745+17461746+ at76_dbg(DBG_MAC80211, "%s()", __func__);17471747+17481748+ mutex_lock(&priv->mtx);17491749+17501750+ ret = at76_submit_rx_urb(priv);17511751+ if (ret < 0) {17521752+ printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",17531753+ wiphy_name(priv->hw->wiphy), ret);17541754+ goto error;17551755+ }17561756+17571757+ at76_startup_device(priv);17581758+17591759+ at76_start_monitor(priv);17601760+17611761+error:17621762+ mutex_unlock(&priv->mtx);17631763+17641764+ return 0;17651765+}17661766+17671767+static void at76_mac80211_stop(struct ieee80211_hw *hw)17681768+{17691769+ struct at76_priv *priv = hw->priv;17701770+17711771+ at76_dbg(DBG_MAC80211, "%s()", __func__);17721772+17731773+ mutex_lock(&priv->mtx);17741774+17751775+ if (!priv->device_unplugged) {17761776+ /* We are called by "ifconfig ethX down", not because the17771777+ * device is not available anymore. */17781778+ at76_set_radio(priv, 0);17791779+17801780+ /* We unlink rx_urb because at76_open() re-submits it.17811781+ * If unplugged, at76_delete_device() takes care of it. */17821782+ usb_kill_urb(priv->rx_urb);17831783+ }17841784+17851785+ mutex_unlock(&priv->mtx);17861786+}17871787+17881788+static int at76_add_interface(struct ieee80211_hw *hw,17891789+ struct ieee80211_if_init_conf *conf)17901790+{17911791+ struct at76_priv *priv = hw->priv;17921792+ int ret = 0;17931793+17941794+ at76_dbg(DBG_MAC80211, "%s()", __func__);17951795+17961796+ mutex_lock(&priv->mtx);17971797+17981798+ switch (conf->type) {17991799+ case NL80211_IFTYPE_STATION:18001800+ priv->iw_mode = IW_MODE_INFRA;18011801+ break;18021802+ default:18031803+ ret = -EOPNOTSUPP;18041804+ goto exit;18051805+ }18061806+18071807+exit:18081808+ mutex_unlock(&priv->mtx);18091809+18101810+ return ret;18111811+}18121812+18131813+static void at76_remove_interface(struct ieee80211_hw *hw,18141814+ struct ieee80211_if_init_conf *conf)18151815+{18161816+ at76_dbg(DBG_MAC80211, "%s()", __func__);18171817+}18181818+18191819+static int at76_join(struct at76_priv *priv)18201820+{18211821+ struct at76_req_join join;18221822+ int ret;18231823+18241824+ memset(&join, 0, sizeof(struct at76_req_join));18251825+ memcpy(join.essid, priv->essid, priv->essid_size);18261826+ join.essid_size = priv->essid_size;18271827+ memcpy(join.bssid, priv->bssid, ETH_ALEN);18281828+ join.bss_type = INFRASTRUCTURE_MODE;18291829+ join.channel = priv->channel;18301830+ join.timeout = cpu_to_le16(2000);18311831+18321832+ at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);18331833+ ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,18341834+ sizeof(struct at76_req_join));18351835+18361836+ if (ret < 0) {18371837+ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",18381838+ wiphy_name(priv->hw->wiphy), ret);18391839+ return 0;18401840+ }18411841+18421842+ ret = at76_wait_completion(priv, CMD_JOIN);18431843+ at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);18441844+ if (ret != CMD_STATUS_COMPLETE) {18451845+ printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",18461846+ wiphy_name(priv->hw->wiphy), ret);18471847+ return 0;18481848+ }18491849+18501850+ at76_set_pm_mode(priv);18511851+18521852+ return 0;18531853+}18541854+18551855+static void at76_dwork_hw_scan(struct work_struct *work)18561856+{18571857+ struct at76_priv *priv = container_of(work, struct at76_priv,18581858+ dwork_hw_scan.work);18591859+ int ret;18601860+18611861+ if (priv->device_unplugged)18621862+ return;18631863+18641864+ mutex_lock(&priv->mtx);18651865+18661866+ ret = at76_get_cmd_status(priv->udev, CMD_SCAN);18671867+ at76_dbg(DBG_MAC80211, "%s: CMD_SCAN status 0x%02x", __func__, ret);18681868+18691869+ /* FIXME: add maximum time for scan to complete */18701870+18711871+ if (ret != CMD_STATUS_COMPLETE) {18721872+ queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,18731873+ SCAN_POLL_INTERVAL);18741874+ goto exit;18751875+ }18761876+18771877+ ieee80211_scan_completed(priv->hw, false);18781878+18791879+ if (is_valid_ether_addr(priv->bssid))18801880+ at76_join(priv);18811881+18821882+ ieee80211_wake_queues(priv->hw);18831883+18841884+exit:18851885+ mutex_unlock(&priv->mtx);18861886+}18871887+18881888+static int at76_hw_scan(struct ieee80211_hw *hw,18891889+ struct cfg80211_scan_request *req)18901890+{18911891+ struct at76_priv *priv = hw->priv;18921892+ struct at76_req_scan scan;18931893+ u8 *ssid = NULL;18941894+ int ret, len = 0;18951895+18961896+ at76_dbg(DBG_MAC80211, "%s():", __func__);18971897+18981898+ if (priv->device_unplugged)18991899+ return 0;19001900+19011901+ mutex_lock(&priv->mtx);19021902+19031903+ ieee80211_stop_queues(hw);19041904+19051905+ memset(&scan, 0, sizeof(struct at76_req_scan));19061906+ memset(scan.bssid, 0xFF, ETH_ALEN);19071907+19081908+ if (req->n_ssids) {19091909+ scan.scan_type = SCAN_TYPE_ACTIVE;19101910+ ssid = req->ssids[0].ssid;19111911+ len = req->ssids[0].ssid_len;19121912+ } else {19131913+ scan.scan_type = SCAN_TYPE_PASSIVE;19141914+ }19151915+19161916+ if (len) {19171917+ memcpy(scan.essid, ssid, len);19181918+ scan.essid_size = len;19191919+ }19201920+19211921+ scan.min_channel_time = cpu_to_le16(priv->scan_min_time);19221922+ scan.max_channel_time = cpu_to_le16(priv->scan_max_time);19231923+ scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000);19241924+ scan.international_scan = 0;19251925+19261926+ at76_dbg(DBG_MAC80211, "%s: sending CMD_SCAN", __func__);19271927+ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));19281928+19291929+ if (ret < 0) {19301930+ err("CMD_SCAN failed: %d", ret);19311931+ goto exit;19321932+ }19331933+19341934+ queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,19351935+ SCAN_POLL_INTERVAL);19361936+19371937+exit:19381938+ mutex_unlock(&priv->mtx);19391939+19401940+ return 0;19411941+}19421942+19431943+static int at76_config(struct ieee80211_hw *hw, u32 changed)19441944+{19451945+ struct at76_priv *priv = hw->priv;19461946+19471947+ at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",19481948+ __func__, hw->conf.channel->hw_value,19491949+ hw->conf.radio_enabled);19501950+ at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");19511951+19521952+ mutex_lock(&priv->mtx);19531953+19541954+ priv->channel = hw->conf.channel->hw_value;19551955+19561956+ if (is_valid_ether_addr(priv->bssid))19571957+ at76_join(priv);19581958+ else19591959+ at76_start_monitor(priv);19601960+19611961+ mutex_unlock(&priv->mtx);19621962+19631963+ return 0;19641964+}19651965+19661966+static int at76_config_interface(struct ieee80211_hw *hw,19671967+ struct ieee80211_vif *vif,19681968+ struct ieee80211_if_conf *conf)19691969+{19701970+ struct at76_priv *priv = hw->priv;19711971+19721972+ at76_dbg(DBG_MAC80211, "%s():", __func__);19731973+ at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:");19741974+19751975+ mutex_lock(&priv->mtx);19761976+19771977+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);19781978+19791979+ if (is_valid_ether_addr(priv->bssid))19801980+ /* mac80211 is joining a bss */19811981+ at76_join(priv);19821982+19831983+ mutex_unlock(&priv->mtx);19841984+19851985+ return 0;19861986+}19871987+19881988+/* must be atomic */19891989+static void at76_configure_filter(struct ieee80211_hw *hw,19901990+ unsigned int changed_flags,19911991+ unsigned int *total_flags, int mc_count,19921992+ struct dev_addr_list *mc_list)19931993+{19941994+ struct at76_priv *priv = hw->priv;19951995+ int flags;19961996+19971997+ at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "19981998+ "total_flags=0x%08x mc_count=%d",19991999+ __func__, changed_flags, *total_flags, mc_count);20002000+20012001+ flags = changed_flags & AT76_SUPPORTED_FILTERS;20022002+ *total_flags = AT76_SUPPORTED_FILTERS;20032003+20042004+ /* Bail out after updating flags to prevent a WARN_ON in mac80211. */20052005+ if (priv->device_unplugged)20062006+ return;20072007+20082008+ /* FIXME: access to priv->promisc should be protected with20092009+ * priv->mtx, but it's impossible because this function needs to be20102010+ * atomic */20112011+20122012+ if (flags && !priv->promisc) {20132013+ /* mac80211 wants us to enable promiscuous mode */20142014+ priv->promisc = 1;20152015+ } else if (!flags && priv->promisc) {20162016+ /* we need to disable promiscuous mode */20172017+ priv->promisc = 0;20182018+ } else20192019+ return;20202020+20212021+ queue_work(hw->workqueue, &priv->work_set_promisc);20222022+}20232023+20242024+static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,20252025+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,20262026+ struct ieee80211_key_conf *key)20272027+{20282028+ struct at76_priv *priv = hw->priv;20292029+20302030+ int i;20312031+20322032+ at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "20332033+ "key->keylen %d",20342034+ __func__, cmd, key->alg, key->keyidx, key->keylen);20352035+20362036+ if (key->alg != ALG_WEP)20372037+ return -EOPNOTSUPP;20382038+20392039+ key->hw_key_idx = key->keyidx;20402040+20412041+ mutex_lock(&priv->mtx);20422042+20432043+ switch (cmd) {20442044+ case SET_KEY:20452045+ memcpy(priv->wep_keys[key->keyidx], key->key, key->keylen);20462046+ priv->wep_keys_len[key->keyidx] = key->keylen;20472047+20482048+ /* FIXME: find out how to do this properly */20492049+ priv->wep_key_id = key->keyidx;20502050+20512051+ break;20522052+ case DISABLE_KEY:20532053+ default:20542054+ priv->wep_keys_len[key->keyidx] = 0;20552055+ break;20562056+ }20572057+20582058+ priv->wep_enabled = 0;20592059+20602060+ for (i = 0; i < WEP_KEYS; i++) {20612061+ if (priv->wep_keys_len[i] != 0)20622062+ priv->wep_enabled = 1;20632063+ }20642064+20652065+ at76_startup_device(priv);20662066+20672067+ mutex_unlock(&priv->mtx);20682068+20692069+ return 0;20702070+}20712071+20722072+static const struct ieee80211_ops at76_ops = {20732073+ .tx = at76_mac80211_tx,20742074+ .add_interface = at76_add_interface,20752075+ .remove_interface = at76_remove_interface,20762076+ .config = at76_config,20772077+ .config_interface = at76_config_interface,20782078+ .configure_filter = at76_configure_filter,20792079+ .start = at76_mac80211_start,20802080+ .stop = at76_mac80211_stop,20812081+ .hw_scan = at76_hw_scan,20822082+ .set_key = at76_set_key,20832083+};20842084+20852085+/* Allocate network device and initialize private data */20862086+static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)20872087+{20882088+ struct ieee80211_hw *hw;20892089+ struct at76_priv *priv;20902090+20912091+ hw = ieee80211_alloc_hw(sizeof(struct at76_priv), &at76_ops);20922092+ if (!hw) {20932093+ printk(KERN_ERR DRIVER_NAME ": could not register"20942094+ " ieee80211_hw\n");20952095+ return NULL;20962096+ }20972097+20982098+ priv = hw->priv;20992099+ priv->hw = hw;21002100+21012101+ priv->udev = udev;21022102+21032103+ mutex_init(&priv->mtx);21042104+ INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);21052105+ INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);21062106+ INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);21072107+21082108+ tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);21092109+21102110+ priv->pm_mode = AT76_PM_OFF;21112111+ priv->pm_period = 0;21122112+21132113+ /* unit us */21142114+ priv->hw->channel_change_time = 100000;21152115+21162116+ return priv;21172117+}21182118+21192119+static int at76_alloc_urbs(struct at76_priv *priv,21202120+ struct usb_interface *interface)21212121+{21222122+ struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;21232123+ int i;21242124+ int buffer_size;21252125+ struct usb_host_interface *iface_desc;21262126+21272127+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);21282128+21292129+ at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,21302130+ interface->altsetting[0].desc.bNumEndpoints);21312131+21322132+ ep_in = NULL;21332133+ ep_out = NULL;21342134+ iface_desc = interface->cur_altsetting;21352135+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {21362136+ endpoint = &iface_desc->endpoint[i].desc;21372137+21382138+ at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",21392139+ __func__, i, endpoint->bEndpointAddress,21402140+ endpoint->bmAttributes);21412141+21422142+ if (!ep_in && usb_endpoint_is_bulk_in(endpoint))21432143+ ep_in = endpoint;21442144+21452145+ if (!ep_out && usb_endpoint_is_bulk_out(endpoint))21462146+ ep_out = endpoint;21472147+ }21482148+21492149+ if (!ep_in || !ep_out) {21502150+ dev_printk(KERN_ERR, &interface->dev,21512151+ "bulk endpoints missing\n");21522152+ return -ENXIO;21532153+ }21542154+21552155+ priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress);21562156+ priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress);21572157+21582158+ priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);21592159+ priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);21602160+ if (!priv->rx_urb || !priv->tx_urb) {21612161+ dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");21622162+ return -ENOMEM;21632163+ }21642164+21652165+ buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;21662166+ priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);21672167+ if (!priv->bulk_out_buffer) {21682168+ dev_printk(KERN_ERR, &interface->dev,21692169+ "cannot allocate output buffer\n");21702170+ return -ENOMEM;21712171+ }21722172+21732173+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);21742174+21752175+ return 0;21762176+}21772177+21782178+static struct ieee80211_rate at76_rates[] = {21792179+ { .bitrate = 10, .hw_value = TX_RATE_1MBIT, },21802180+ { .bitrate = 20, .hw_value = TX_RATE_2MBIT, },21812181+ { .bitrate = 55, .hw_value = TX_RATE_5_5MBIT, },21822182+ { .bitrate = 110, .hw_value = TX_RATE_11MBIT, },21832183+};21842184+21852185+static struct ieee80211_channel at76_channels[] = {21862186+ { .center_freq = 2412, .hw_value = 1 },21872187+ { .center_freq = 2417, .hw_value = 2 },21882188+ { .center_freq = 2422, .hw_value = 3 },21892189+ { .center_freq = 2427, .hw_value = 4 },21902190+ { .center_freq = 2432, .hw_value = 5 },21912191+ { .center_freq = 2437, .hw_value = 6 },21922192+ { .center_freq = 2442, .hw_value = 7 },21932193+ { .center_freq = 2447, .hw_value = 8 },21942194+ { .center_freq = 2452, .hw_value = 9 },21952195+ { .center_freq = 2457, .hw_value = 10 },21962196+ { .center_freq = 2462, .hw_value = 11 },21972197+ { .center_freq = 2467, .hw_value = 12 },21982198+ { .center_freq = 2472, .hw_value = 13 },21992199+ { .center_freq = 2484, .hw_value = 14 }22002200+};22012201+22022202+static struct ieee80211_supported_band at76_supported_band = {22032203+ .channels = at76_channels,22042204+ .n_channels = ARRAY_SIZE(at76_channels),22052205+ .bitrates = at76_rates,22062206+ .n_bitrates = ARRAY_SIZE(at76_rates),22072207+};22082208+22092209+/* Register network device and initialize the hardware */22102210+static int at76_init_new_device(struct at76_priv *priv,22112211+ struct usb_interface *interface)22122212+{22132213+ int ret;22142214+22152215+ /* set up the endpoint information */22162216+ /* check out the endpoints */22172217+22182218+ at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",22192219+ interface->cur_altsetting->desc.bNumEndpoints);22202220+22212221+ ret = at76_alloc_urbs(priv, interface);22222222+ if (ret < 0)22232223+ goto exit;22242224+22252225+ /* MAC address */22262226+ ret = at76_get_hw_config(priv);22272227+ if (ret < 0) {22282228+ dev_printk(KERN_ERR, &interface->dev,22292229+ "cannot get MAC address\n");22302230+ goto exit;22312231+ }22322232+22332233+ priv->domain = at76_get_reg_domain(priv->regulatory_domain);22342234+22352235+ priv->channel = DEF_CHANNEL;22362236+ priv->iw_mode = IW_MODE_INFRA;22372237+ priv->rts_threshold = DEF_RTS_THRESHOLD;22382238+ priv->frag_threshold = DEF_FRAG_THRESHOLD;22392239+ priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT;22402240+ priv->txrate = TX_RATE_AUTO;22412241+ priv->preamble_type = PREAMBLE_TYPE_LONG;22422242+ priv->beacon_period = 100;22432243+ priv->auth_mode = WLAN_AUTH_OPEN;22442244+ priv->scan_min_time = DEF_SCAN_MIN_TIME;22452245+ priv->scan_max_time = DEF_SCAN_MAX_TIME;22462246+ priv->scan_mode = SCAN_TYPE_ACTIVE;22472247+ priv->device_unplugged = 0;22482248+22492249+ /* mac80211 initialisation */22502250+ priv->hw->wiphy->max_scan_ssids = 1;22512251+ priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);22522252+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;22532253+ priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |22542254+ IEEE80211_HW_SIGNAL_UNSPEC;22552255+ priv->hw->max_signal = 100;22562256+22572257+ SET_IEEE80211_DEV(priv->hw, &interface->dev);22582258+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);22592259+22602260+ ret = ieee80211_register_hw(priv->hw);22612261+ if (ret) {22622262+ printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",22632263+ ret);22642264+ goto exit;22652265+ }22662266+22672267+ priv->mac80211_registered = 1;22682268+22692269+ printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",22702270+ wiphy_name(priv->hw->wiphy),22712271+ dev_name(&interface->dev), mac2str(priv->mac_addr),22722272+ priv->fw_version.major, priv->fw_version.minor,22732273+ priv->fw_version.patch, priv->fw_version.build);22742274+ printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",22752275+ wiphy_name(priv->hw->wiphy),22762276+ priv->regulatory_domain, priv->domain->name);22772277+22782278+exit:22792279+ return ret;22802280+}22812281+22822282+static void at76_delete_device(struct at76_priv *priv)22832283+{22842284+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);22852285+22862286+ /* The device is gone, don't bother turning it off */22872287+ priv->device_unplugged = 1;22882288+22892289+ tasklet_kill(&priv->rx_tasklet);22902290+22912291+ if (priv->mac80211_registered) {22922292+ cancel_delayed_work(&priv->dwork_hw_scan);22932293+ flush_workqueue(priv->hw->workqueue);22942294+ ieee80211_unregister_hw(priv->hw);22952295+ }22962296+22972297+ if (priv->tx_urb) {22982298+ usb_kill_urb(priv->tx_urb);22992299+ usb_free_urb(priv->tx_urb);23002300+ }23012301+ if (priv->rx_urb) {23022302+ usb_kill_urb(priv->rx_urb);23032303+ usb_free_urb(priv->rx_urb);23042304+ }23052305+23062306+ at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);23072307+23082308+ kfree(priv->bulk_out_buffer);23092309+23102310+ del_timer_sync(&ledtrig_tx_timer);23112311+23122312+ if (priv->rx_skb)23132313+ kfree_skb(priv->rx_skb);23142314+23152315+ usb_put_dev(priv->udev);23162316+23172317+ at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",23182318+ __func__);23192319+ ieee80211_free_hw(priv->hw);23202320+23212321+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);23222322+}23232323+23242324+static int at76_probe(struct usb_interface *interface,23252325+ const struct usb_device_id *id)23262326+{23272327+ int ret;23282328+ struct at76_priv *priv;23292329+ struct fwentry *fwe;23302330+ struct usb_device *udev;23312331+ int op_mode;23322332+ int need_ext_fw = 0;23332333+ struct mib_fw_version fwv;23342334+ int board_type = (int)id->driver_info;23352335+23362336+ udev = usb_get_dev(interface_to_usbdev(interface));23372337+23382338+ /* Load firmware into kernel memory */23392339+ fwe = at76_load_firmware(udev, board_type);23402340+ if (!fwe) {23412341+ ret = -ENOENT;23422342+ goto error;23432343+ }23442344+23452345+ op_mode = at76_get_op_mode(udev);23462346+23472347+ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);23482348+23492349+ /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ???23502350+ we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */23512351+23522352+ if (op_mode == OPMODE_HW_CONFIG_MODE) {23532353+ dev_printk(KERN_ERR, &interface->dev,23542354+ "cannot handle a device in HW_CONFIG_MODE\n");23552355+ ret = -EBUSY;23562356+ goto error;23572357+ }23582358+23592359+ if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH23602360+ && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {23612361+ /* download internal firmware part */23622362+ dev_printk(KERN_DEBUG, &interface->dev,23632363+ "downloading internal firmware\n");23642364+ ret = at76_load_internal_fw(udev, fwe);23652365+ if (ret < 0) {23662366+ dev_printk(KERN_ERR, &interface->dev,23672367+ "error %d downloading internal firmware\n",23682368+ ret);23692369+ goto error;23702370+ }23712371+ usb_put_dev(udev);23722372+ return ret;23732373+ }23742374+23752375+ /* Internal firmware already inside the device. Get firmware23762376+ * version to test if external firmware is loaded.23772377+ * This works only for newer firmware, e.g. the Intersil 0.90.x23782378+ * says "control timeout on ep0in" and subsequent23792379+ * at76_get_op_mode() fail too :-( */23802380+23812381+ /* if version >= 0.100.x.y or device with built-in flash we can23822382+ * query the device for the fw version */23832383+ if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)23842384+ || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {23852385+ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));23862386+ if (ret < 0 || (fwv.major | fwv.minor) == 0)23872387+ need_ext_fw = 1;23882388+ } else23892389+ /* No way to check firmware version, reload to be sure */23902390+ need_ext_fw = 1;23912391+23922392+ if (need_ext_fw) {23932393+ dev_printk(KERN_DEBUG, &interface->dev,23942394+ "downloading external firmware\n");23952395+23962396+ ret = at76_load_external_fw(udev, fwe);23972397+ if (ret)23982398+ goto error;23992399+24002400+ /* Re-check firmware version */24012401+ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));24022402+ if (ret < 0) {24032403+ dev_printk(KERN_ERR, &interface->dev,24042404+ "error %d getting firmware version\n", ret);24052405+ goto error;24062406+ }24072407+ }24082408+24092409+ priv = at76_alloc_new_device(udev);24102410+ if (!priv) {24112411+ ret = -ENOMEM;24122412+ goto error;24132413+ }24142414+24152415+ usb_set_intfdata(interface, priv);24162416+24172417+ memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));24182418+ priv->board_type = board_type;24192419+24202420+ ret = at76_init_new_device(priv, interface);24212421+ if (ret < 0)24222422+ at76_delete_device(priv);24232423+24242424+ return ret;24252425+24262426+error:24272427+ usb_put_dev(udev);24282428+ return ret;24292429+}24302430+24312431+static void at76_disconnect(struct usb_interface *interface)24322432+{24332433+ struct at76_priv *priv;24342434+24352435+ priv = usb_get_intfdata(interface);24362436+ usb_set_intfdata(interface, NULL);24372437+24382438+ /* Disconnect after loading internal firmware */24392439+ if (!priv)24402440+ return;24412441+24422442+ printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy));24432443+ at76_delete_device(priv);24442444+ dev_printk(KERN_INFO, &interface->dev, "disconnected\n");24452445+}24462446+24472447+/* Structure for registering this driver with the USB subsystem */24482448+static struct usb_driver at76_driver = {24492449+ .name = DRIVER_NAME,24502450+ .probe = at76_probe,24512451+ .disconnect = at76_disconnect,24522452+ .id_table = dev_table,24532453+};24542454+24552455+static int __init at76_mod_init(void)24562456+{24572457+ int result;24582458+24592459+ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n");24602460+24612461+ mutex_init(&fw_mutex);24622462+24632463+ /* register this driver with the USB subsystem */24642464+ result = usb_register(&at76_driver);24652465+ if (result < 0)24662466+ printk(KERN_ERR DRIVER_NAME24672467+ ": usb_register failed (status %d)\n", result);24682468+24692469+ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);24702470+ return result;24712471+}24722472+24732473+static void __exit at76_mod_exit(void)24742474+{24752475+ int i;24762476+24772477+ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");24782478+ usb_deregister(&at76_driver);24792479+ for (i = 0; i < ARRAY_SIZE(firmwares); i++) {24802480+ if (firmwares[i].fw)24812481+ release_firmware(firmwares[i].fw);24822482+ }24832483+ led_trigger_unregister_simple(ledtrig_tx);24842484+}24852485+24862486+module_param_named(debug, at76_debug, uint, 0600);24872487+MODULE_PARM_DESC(debug, "Debugging level");24882488+24892489+module_init(at76_mod_init);24902490+module_exit(at76_mod_exit);24912491+24922492+MODULE_AUTHOR("Oliver Kurth <oku@masqmail.cx>");24932493+MODULE_AUTHOR("Joerg Albert <joerg.albert@gmx.de>");24942494+MODULE_AUTHOR("Alex <alex@foogod.com>");24952495+MODULE_AUTHOR("Nick Jones");24962496+MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");24972497+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");24982498+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");24992499+MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");25002500+MODULE_DESCRIPTION(DRIVER_DESC);25012501+MODULE_LICENSE("GPL");
+463
drivers/net/wireless/at76c50x-usb.h
···11+/*22+ * Copyright (c) 2002,2003 Oliver Kurth33+ * (c) 2003,2004 Joerg Albert <joerg.albert@gmx.de>44+ * (c) 2007 Guido Guenther <agx@sigxcpu.org>55+ *66+ * This program is free software; you can redistribute it and/or77+ * modify it under the terms of the GNU General Public License as88+ * published by the Free Software Foundation; either version 2 of99+ * the License, or (at your option) any later version.1010+ *1111+ * This driver was based on information from the Sourceforge driver1212+ * released and maintained by Atmel:1313+ *1414+ * http://sourceforge.net/projects/atmelwlandriver/1515+ *1616+ * Although the code was completely re-written,1717+ * it would have been impossible without Atmel's decision to1818+ * release an Open Source driver (unfortunately the firmware was1919+ * kept binary only). Thanks for that decision to Atmel!2020+ */2121+2222+#ifndef _AT76_USB_H2323+#define _AT76_USB_H2424+2525+/* Board types */2626+enum board_type {2727+ BOARD_503_ISL3861 = 1,2828+ BOARD_503_ISL3863 = 2,2929+ BOARD_503 = 3,3030+ BOARD_503_ACC = 4,3131+ BOARD_505 = 5,3232+ BOARD_505_2958 = 6,3333+ BOARD_505A = 7,3434+ BOARD_505AMX = 83535+};3636+3737+#define CMD_STATUS_IDLE 0x003838+#define CMD_STATUS_COMPLETE 0x013939+#define CMD_STATUS_UNKNOWN 0x024040+#define CMD_STATUS_INVALID_PARAMETER 0x034141+#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x044242+#define CMD_STATUS_TIME_OUT 0x074343+#define CMD_STATUS_IN_PROGRESS 0x084444+#define CMD_STATUS_HOST_FAILURE 0xff4545+#define CMD_STATUS_SCAN_FAILED 0xf04646+4747+/* answers to get op mode */4848+#define OPMODE_NONE 0x004949+#define OPMODE_NORMAL_NIC_WITH_FLASH 0x015050+#define OPMODE_HW_CONFIG_MODE 0x025151+#define OPMODE_DFU_MODE_WITH_FLASH 0x035252+#define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x045353+5454+#define CMD_SET_MIB 0x015555+#define CMD_GET_MIB 0x025656+#define CMD_SCAN 0x035757+#define CMD_JOIN 0x045858+#define CMD_START_IBSS 0x055959+#define CMD_RADIO_ON 0x066060+#define CMD_RADIO_OFF 0x076161+#define CMD_STARTUP 0x0B6262+6363+#define MIB_LOCAL 0x016464+#define MIB_MAC_ADDR 0x026565+#define MIB_MAC 0x036666+#define MIB_MAC_MGMT 0x056767+#define MIB_MAC_WEP 0x066868+#define MIB_PHY 0x076969+#define MIB_FW_VERSION 0x087070+#define MIB_MDOMAIN 0x097171+7272+#define ADHOC_MODE 17373+#define INFRASTRUCTURE_MODE 27474+7575+/* values for struct mib_local, field preamble_type */7676+#define PREAMBLE_TYPE_LONG 07777+#define PREAMBLE_TYPE_SHORT 17878+#define PREAMBLE_TYPE_AUTO 27979+8080+/* values for tx_rate */8181+#define TX_RATE_1MBIT 08282+#define TX_RATE_2MBIT 18383+#define TX_RATE_5_5MBIT 28484+#define TX_RATE_11MBIT 38585+#define TX_RATE_AUTO 48686+8787+/* power management modes */8888+#define AT76_PM_OFF 18989+#define AT76_PM_ON 29090+#define AT76_PM_SMART 39191+9292+struct hwcfg_r505 {9393+ u8 cr39_values[14];9494+ u8 reserved1[14];9595+ u8 bb_cr[14];9696+ u8 pidvid[4];9797+ u8 mac_addr[ETH_ALEN];9898+ u8 regulatory_domain;9999+ u8 reserved2[14];100100+ u8 cr15_values[14];101101+ u8 reserved3[3];102102+} __attribute__((packed));103103+104104+struct hwcfg_rfmd {105105+ u8 cr20_values[14];106106+ u8 cr21_values[14];107107+ u8 bb_cr[14];108108+ u8 pidvid[4];109109+ u8 mac_addr[ETH_ALEN];110110+ u8 regulatory_domain;111111+ u8 low_power_values[14];112112+ u8 normal_power_values[14];113113+ u8 reserved1[3];114114+} __attribute__((packed));115115+116116+struct hwcfg_intersil {117117+ u8 mac_addr[ETH_ALEN];118118+ u8 cr31_values[14];119119+ u8 cr58_values[14];120120+ u8 pidvid[4];121121+ u8 regulatory_domain;122122+ u8 reserved[1];123123+} __attribute__((packed));124124+125125+union at76_hwcfg {126126+ struct hwcfg_intersil i;127127+ struct hwcfg_rfmd r3;128128+ struct hwcfg_r505 r5;129129+};130130+131131+#define WEP_SMALL_KEY_LEN (40 / 8)132132+#define WEP_LARGE_KEY_LEN (104 / 8)133133+#define WEP_KEYS (4)134134+135135+struct at76_card_config {136136+ u8 exclude_unencrypted;137137+ u8 promiscuous_mode;138138+ u8 short_retry_limit;139139+ u8 encryption_type;140140+ __le16 rts_threshold;141141+ __le16 fragmentation_threshold; /* 256..2346 */142142+ u8 basic_rate_set[4];143143+ u8 auto_rate_fallback; /* 0,1 */144144+ u8 channel;145145+ u8 privacy_invoked;146146+ u8 wep_default_key_id; /* 0..3 */147147+ u8 current_ssid[32];148148+ u8 wep_default_key_value[4][WEP_LARGE_KEY_LEN];149149+ u8 ssid_len;150150+ u8 short_preamble;151151+ __le16 beacon_period;152152+} __attribute__((packed));153153+154154+struct at76_command {155155+ u8 cmd;156156+ u8 reserved;157157+ __le16 size;158158+ u8 data[0];159159+} __attribute__((packed));160160+161161+/* Length of Atmel-specific Rx header before 802.11 frame */162162+#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)163163+164164+struct at76_rx_buffer {165165+ __le16 wlength;166166+ u8 rx_rate;167167+ u8 newbss;168168+ u8 fragmentation;169169+ u8 rssi;170170+ u8 link_quality;171171+ u8 noise_level;172172+ __le32 rx_time;173173+ u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];174174+} __attribute__((packed));175175+176176+/* Length of Atmel-specific Tx header before 802.11 frame */177177+#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)178178+179179+struct at76_tx_buffer {180180+ __le16 wlength;181181+ u8 tx_rate;182182+ u8 padding;183183+ u8 reserved[4];184184+ u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];185185+} __attribute__((packed));186186+187187+/* defines for scan_type below */188188+#define SCAN_TYPE_ACTIVE 0189189+#define SCAN_TYPE_PASSIVE 1190190+191191+struct at76_req_scan {192192+ u8 bssid[ETH_ALEN];193193+ u8 essid[32];194194+ u8 scan_type;195195+ u8 channel;196196+ __le16 probe_delay;197197+ __le16 min_channel_time;198198+ __le16 max_channel_time;199199+ u8 essid_size;200200+ u8 international_scan;201201+} __attribute__((packed));202202+203203+struct at76_req_ibss {204204+ u8 bssid[ETH_ALEN];205205+ u8 essid[32];206206+ u8 bss_type;207207+ u8 channel;208208+ u8 essid_size;209209+ u8 reserved[3];210210+} __attribute__((packed));211211+212212+struct at76_req_join {213213+ u8 bssid[ETH_ALEN];214214+ u8 essid[32];215215+ u8 bss_type;216216+ u8 channel;217217+ __le16 timeout;218218+ u8 essid_size;219219+ u8 reserved;220220+} __attribute__((packed));221221+222222+struct set_mib_buffer {223223+ u8 type;224224+ u8 size;225225+ u8 index;226226+ u8 reserved;227227+ union {228228+ u8 byte;229229+ __le16 word;230230+ u8 addr[ETH_ALEN];231231+ } data;232232+} __attribute__((packed));233233+234234+struct mib_local {235235+ u16 reserved0;236236+ u8 beacon_enable;237237+ u8 txautorate_fallback;238238+ u8 reserved1;239239+ u8 ssid_size;240240+ u8 promiscuous_mode;241241+ u16 reserved2;242242+ u8 preamble_type;243243+ u16 reserved3;244244+} __attribute__((packed));245245+246246+struct mib_mac_addr {247247+ u8 mac_addr[ETH_ALEN];248248+ u8 res[2]; /* ??? */249249+ u8 group_addr[4][ETH_ALEN];250250+ u8 group_addr_status[4];251251+} __attribute__((packed));252252+253253+struct mib_mac {254254+ __le32 max_tx_msdu_lifetime;255255+ __le32 max_rx_lifetime;256256+ __le16 frag_threshold;257257+ __le16 rts_threshold;258258+ __le16 cwmin;259259+ __le16 cwmax;260260+ u8 short_retry_time;261261+ u8 long_retry_time;262262+ u8 scan_type; /* active or passive */263263+ u8 scan_channel;264264+ __le16 probe_delay; /* delay before ProbeReq in active scan, RO */265265+ __le16 min_channel_time;266266+ __le16 max_channel_time;267267+ __le16 listen_interval;268268+ u8 desired_ssid[32];269269+ u8 desired_bssid[ETH_ALEN];270270+ u8 desired_bsstype; /* ad-hoc or infrastructure */271271+ u8 reserved2;272272+} __attribute__((packed));273273+274274+struct mib_mac_mgmt {275275+ __le16 beacon_period;276276+ __le16 CFP_max_duration;277277+ __le16 medium_occupancy_limit;278278+ __le16 station_id; /* assoc id */279279+ __le16 ATIM_window;280280+ u8 CFP_mode;281281+ u8 privacy_option_implemented;282282+ u8 DTIM_period;283283+ u8 CFP_period;284284+ u8 current_bssid[ETH_ALEN];285285+ u8 current_essid[32];286286+ u8 current_bss_type;287287+ u8 power_mgmt_mode;288288+ /* rfmd and 505 */289289+ u8 ibss_change;290290+ u8 res;291291+ u8 multi_domain_capability_implemented;292292+ u8 multi_domain_capability_enabled;293293+ u8 country_string[3];294294+ u8 reserved[3];295295+} __attribute__((packed));296296+297297+struct mib_mac_wep {298298+ u8 privacy_invoked; /* 0 disable encr., 1 enable encr */299299+ u8 wep_default_key_id;300300+ u8 wep_key_mapping_len;301301+ u8 exclude_unencrypted;302302+ __le32 wep_icv_error_count;303303+ __le32 wep_excluded_count;304304+ u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];305305+ u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */306306+} __attribute__((packed));307307+308308+struct mib_phy {309309+ __le32 ed_threshold;310310+311311+ __le16 slot_time;312312+ __le16 sifs_time;313313+ __le16 preamble_length;314314+ __le16 plcp_header_length;315315+ __le16 mpdu_max_length;316316+ __le16 cca_mode_supported;317317+318318+ u8 operation_rate_set[4];319319+ u8 channel_id;320320+ u8 current_cca_mode;321321+ u8 phy_type;322322+ u8 current_reg_domain;323323+} __attribute__((packed));324324+325325+struct mib_fw_version {326326+ u8 major;327327+ u8 minor;328328+ u8 patch;329329+ u8 build;330330+} __attribute__((packed));331331+332332+struct mib_mdomain {333333+ u8 tx_powerlevel[14];334334+ u8 channel_list[14]; /* 0 for invalid channels */335335+} __attribute__((packed));336336+337337+struct at76_fw_header {338338+ __le32 crc; /* CRC32 of the whole image */339339+ __le32 board_type; /* firmware compatibility code */340340+ u8 build; /* firmware build number */341341+ u8 patch; /* firmware patch level */342342+ u8 minor; /* firmware minor version */343343+ u8 major; /* firmware major version */344344+ __le32 str_offset; /* offset of the copyright string */345345+ __le32 int_fw_offset; /* internal firmware image offset */346346+ __le32 int_fw_len; /* internal firmware image length */347347+ __le32 ext_fw_offset; /* external firmware image offset */348348+ __le32 ext_fw_len; /* external firmware image length */349349+} __attribute__((packed));350350+351351+/* a description of a regulatory domain and the allowed channels */352352+struct reg_domain {353353+ u16 code;354354+ char const *name;355355+ u32 channel_map; /* if bit N is set, channel (N+1) is allowed */356356+};357357+358358+/* Data for one loaded firmware file */359359+struct fwentry {360360+ const char *const fwname;361361+ const struct firmware *fw;362362+ int extfw_size;363363+ int intfw_size;364364+ /* pointer to loaded firmware, no need to free */365365+ u8 *extfw; /* external firmware, extfw_size bytes long */366366+ u8 *intfw; /* internal firmware, intfw_size bytes long */367367+ enum board_type board_type; /* board type */368368+ struct mib_fw_version fw_version;369369+ int loaded; /* Loaded and parsed successfully */370370+};371371+372372+struct at76_priv {373373+ struct usb_device *udev; /* USB device pointer */374374+375375+ struct sk_buff *rx_skb; /* skbuff for receiving data */376376+ struct sk_buff *tx_skb; /* skbuff for transmitting data */377377+ void *bulk_out_buffer; /* buffer for sending data */378378+379379+ struct urb *tx_urb; /* URB for sending data */380380+ struct urb *rx_urb; /* URB for receiving data */381381+382382+ unsigned int tx_pipe; /* bulk out pipe */383383+ unsigned int rx_pipe; /* bulk in pipe */384384+385385+ struct mutex mtx; /* locks this structure */386386+387387+ /* work queues */388388+ struct work_struct work_set_promisc;389389+ struct work_struct work_submit_rx;390390+ struct delayed_work dwork_hw_scan;391391+392392+ struct tasklet_struct rx_tasklet;393393+394394+ /* the WEP stuff */395395+ int wep_enabled; /* 1 if WEP is enabled */396396+ int wep_key_id; /* key id to be used */397397+ u8 wep_keys[WEP_KEYS][WEP_LARGE_KEY_LEN]; /* WEP keys */398398+ u8 wep_keys_len[WEP_KEYS]; /* length of WEP keys */399399+400400+ int channel;401401+ int iw_mode;402402+ u8 bssid[ETH_ALEN];403403+ u8 essid[IW_ESSID_MAX_SIZE];404404+ int essid_size;405405+ int radio_on;406406+ int promisc;407407+408408+ int preamble_type; /* 0 - long, 1 - short, 2 - auto */409409+ int auth_mode; /* authentication type: 0 open, 1 shared key */410410+ int txrate; /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */411411+ int frag_threshold; /* threshold for fragmentation of tx packets */412412+ int rts_threshold; /* threshold for RTS mechanism */413413+ int short_retry_limit;414414+415415+ int scan_min_time; /* scan min channel time */416416+ int scan_max_time; /* scan max channel time */417417+ int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */418418+ int scan_need_any; /* if set, need to scan for any ESSID */419419+420420+ u16 assoc_id; /* current association ID, if associated */421421+422422+ u8 pm_mode; /* power management mode */423423+ u32 pm_period; /* power management period in microseconds */424424+425425+ struct reg_domain const *domain; /* reg domain description */426426+427427+ /* These fields contain HW config provided by the device (not all of428428+ * these fields are used by all board types) */429429+ u8 mac_addr[ETH_ALEN];430430+ u8 regulatory_domain;431431+432432+ struct at76_card_config card_config;433433+434434+ enum board_type board_type;435435+ struct mib_fw_version fw_version;436436+437437+ unsigned int device_unplugged:1;438438+ unsigned int netdev_registered:1;439439+ struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */440440+441441+ int beacon_period; /* period of mgmt beacons, Kus */442442+443443+ struct ieee80211_hw *hw;444444+ int mac80211_registered;445445+};446446+447447+#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS448448+449449+#define SCAN_POLL_INTERVAL (HZ / 4)450450+451451+#define CMD_COMPLETION_TIMEOUT (5 * HZ)452452+453453+#define DEF_RTS_THRESHOLD 1536454454+#define DEF_FRAG_THRESHOLD 1536455455+#define DEF_SHORT_RETRY_LIMIT 8456456+#define DEF_CHANNEL 10457457+#define DEF_SCAN_MIN_TIME 10458458+#define DEF_SCAN_MAX_TIME 120459459+460460+/* the max padding size for tx in bytes (see calc_padding) */461461+#define MAX_PADDING_SIZE 53462462+463463+#endif /* _AT76_USB_H */
+41-43
drivers/net/wireless/ath5k/base.c
···350350static void ath5k_beacon_send(struct ath5k_softc *sc);351351static void ath5k_beacon_config(struct ath5k_softc *sc);352352static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);353353+static void ath5k_tasklet_beacon(unsigned long data);353354354355static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)355356{···790789 tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);791790 tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);792791 tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);792792+ tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);793793 setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);794794795795 ret = ath5k_eeprom_read_mac(ah, mac);···1220121812211219 pktlen = skb->len;1222122012211221+ if (info->control.hw_key) {12221222+ keyidx = info->control.hw_key->hw_key_idx;12231223+ pktlen += info->control.hw_key->icv_len;12241224+ }12231225 if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {12241226 flags |= AR5K_TXDESC_RTSENA;12251227 cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;···12351229 cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;12361230 duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,12371231 sc->vif, pktlen, info));12381238- }12391239-12401240- if (info->control.hw_key) {12411241- keyidx = info->control.hw_key->hw_key_idx;12421242- pktlen += info->control.hw_key->icv_len;12431232 }12441233 ret = ah->ah_setup_tx_desc(ah, ds, pktlen,12451234 ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,···17011700 }17021701}1703170217031703+static void ath5k_tasklet_beacon(unsigned long data)17041704+{17051705+ struct ath5k_softc *sc = (struct ath5k_softc *) data;17061706+17071707+ /*17081708+ * Software beacon alert--time to send a beacon.17091709+ *17101710+ * In IBSS mode we use this interrupt just to17111711+ * keep track of the next TBTT (target beacon17121712+ * transmission time) in order to detect wether17131713+ * automatic TSF updates happened.17141714+ */17151715+ if (sc->opmode == NL80211_IFTYPE_ADHOC) {17161716+ /* XXX: only if VEOL suppported */17171717+ u64 tsf = ath5k_hw_get_tsf64(sc->ah);17181718+ sc->nexttbtt += sc->bintval;17191719+ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,17201720+ "SWBA nexttbtt: %x hw_tu: %x "17211721+ "TSF: %llx\n",17221722+ sc->nexttbtt,17231723+ TSF_TO_TU(tsf),17241724+ (unsigned long long) tsf);17251725+ } else {17261726+ spin_lock(&sc->block);17271727+ ath5k_beacon_send(sc);17281728+ spin_unlock(&sc->block);17291729+ }17301730+}1704173117051732static void17061733ath5k_tasklet_rx(unsigned long data)···20692040 * frame contents are done as needed and the slot time is20702041 * also adjusted based on current state.20712042 *20722072- * this is usually called from interrupt context (ath5k_intr())20732073- * but also from ath5k_beacon_config() in IBSS mode which in turn20742074- * can be called from a tasklet and user context20432043+ * This is called from software irq context (beacontq or restq20442044+ * tasklets) or user context from ath5k_beacon_config.20752045 */20762046static void20772047ath5k_beacon_send(struct ath5k_softc *sc)···22442216ath5k_beacon_config(struct ath5k_softc *sc)22452217{22462218 struct ath5k_hw *ah = sc->ah;22192219+ unsigned long flags;2247222022482221 ath5k_hw_set_imr(ah, 0);22492222 sc->bmisscount = 0;···2266223722672238 if (sc->opmode == NL80211_IFTYPE_ADHOC) {22682239 if (ath5k_hw_hasveol(ah)) {22692269- spin_lock(&sc->block);22402240+ spin_lock_irqsave(&sc->block, flags);22702241 ath5k_beacon_send(sc);22712271- spin_unlock(&sc->block);22422242+ spin_unlock_irqrestore(&sc->block, flags);22722243 }22732244 } else22742245 ath5k_beacon_update_timers(sc, -1);···24202391 tasklet_kill(&sc->rxtq);24212392 tasklet_kill(&sc->txtq);24222393 tasklet_kill(&sc->restq);23942394+ tasklet_kill(&sc->beacontq);2423239524242396 return ret;24252397}···24382408 return IRQ_NONE;2439240924402410 do {24412441- /*24422442- * Figure out the reason(s) for the interrupt. Note24432443- * that get_isr returns a pseudo-ISR that may include24442444- * bits we haven't explicitly enabled so we mask the24452445- * value to insure we only process bits we requested.24462446- */24472411 ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */24482412 ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",24492413 status, sc->imask);24502450- status &= sc->imask; /* discard unasked for bits */24512414 if (unlikely(status & AR5K_INT_FATAL)) {24522415 /*24532416 * Fatal errors are unrecoverable.···24512428 tasklet_schedule(&sc->restq);24522429 } else {24532430 if (status & AR5K_INT_SWBA) {24542454- /*24552455- * Software beacon alert--time to send a beacon.24562456- * Handle beacon transmission directly; deferring24572457- * this is too slow to meet timing constraints24582458- * under load.24592459- *24602460- * In IBSS mode we use this interrupt just to24612461- * keep track of the next TBTT (target beacon24622462- * transmission time) in order to detect wether24632463- * automatic TSF updates happened.24642464- */24652465- if (sc->opmode == NL80211_IFTYPE_ADHOC) {24662466- /* XXX: only if VEOL suppported */24672467- u64 tsf = ath5k_hw_get_tsf64(ah);24682468- sc->nexttbtt += sc->bintval;24692469- ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,24702470- "SWBA nexttbtt: %x hw_tu: %x "24712471- "TSF: %llx\n",24722472- sc->nexttbtt,24732473- TSF_TO_TU(tsf),24742474- (unsigned long long) tsf);24752475- } else {24762476- spin_lock(&sc->block);24772477- ath5k_beacon_send(sc);24782478- spin_unlock(&sc->block);24792479- }24312431+ tasklet_schedule(&sc->beacontq);24802432 }24812433 if (status & AR5K_INT_RXEOL) {24822434 /*
···106106 }107107};108108109109+static inline bool is_wwr_sku(u16 regd)110110+{111111+ return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||112112+ (regd == WORLD);113113+}114114+109115static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)110116{111117 return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;112118}113119114114-u16 ath9k_regd_get_rd(struct ath_hw *ah)115115-{116116- return ath9k_regd_get_eepromRD(ah);117117-}118118-119120bool ath9k_is_world_regd(struct ath_hw *ah)120121{121121- return isWwrSKU(ah);122122+ return is_wwr_sku(ath9k_regd_get_eepromRD(ah));122123}123124124125const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)···160159}161160162161/*163163- * Enable adhoc on 5 GHz if allowed by 11d.164164- * Remove passive scan if channel is allowed by 11d,165165- * except when on radar frequencies.162162+ * N.B: These exception rules do not apply radar freqs.163163+ *164164+ * - We enable adhoc (or beaconing) if allowed by 11d165165+ * - We enable active scan if the channel is allowed by 11d166166+ * - If no country IE has been processed and a we determine we have167167+ * received a beacon on a channel we can enable active scan and168168+ * adhoc (or beaconing).166169 */167167-static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,170170+static void ath9k_reg_apply_beaconing_flags(struct wiphy *wiphy,168171 enum reg_set_by setby)169172{173173+ enum ieee80211_band band;170174 struct ieee80211_supported_band *sband;171175 const struct ieee80211_reg_rule *reg_rule;172176 struct ieee80211_channel *ch;···179173 u32 bandwidth = 0;180174 int r;181175182182- if (setby != REGDOM_SET_BY_COUNTRY_IE)183183- return;184184- if (!wiphy->bands[IEEE80211_BAND_5GHZ])185185- return;176176+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {186177187187- sband = wiphy->bands[IEEE80211_BAND_5GHZ];188188- for (i = 0; i < sband->n_channels; i++) {189189- ch = &sband->channels[i];190190- r = freq_reg_info(wiphy, ch->center_freq,191191- &bandwidth, ®_rule);192192- if (r)178178+ if (!wiphy->bands[band])193179 continue;194194- /* If 11d had a rule for this channel ensure we enable adhoc195195- * if it allows us to use it. Note that we would have disabled196196- * it by applying our static world regdomain by default during197197- * probe */198198- if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))199199- ch->flags &= ~IEEE80211_CHAN_NO_IBSS;200200- if (!ath9k_is_radar_freq(ch->center_freq))201201- continue;202202- if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))203203- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;180180+181181+ sband = wiphy->bands[band];182182+183183+ for (i = 0; i < sband->n_channels; i++) {184184+185185+ ch = &sband->channels[i];186186+187187+ if (ath9k_is_radar_freq(ch->center_freq) ||188188+ (ch->flags & IEEE80211_CHAN_RADAR))189189+ continue;190190+191191+ if (setby == REGDOM_SET_BY_COUNTRY_IE) {192192+ r = freq_reg_info(wiphy, ch->center_freq,193193+ &bandwidth, ®_rule);194194+ if (r)195195+ continue;196196+ /*197197+ * If 11d had a rule for this channel ensure198198+ * we enable adhoc/beaconing if it allows us to199199+ * use it. Note that we would have disabled it200200+ * by applying our static world regdomain by201201+ * default during init, prior to calling our202202+ * regulatory_hint().203203+ */204204+ if (!(reg_rule->flags &205205+ NL80211_RRF_NO_IBSS))206206+ ch->flags &=207207+ ~IEEE80211_CHAN_NO_IBSS;208208+ if (!(reg_rule->flags &209209+ NL80211_RRF_PASSIVE_SCAN))210210+ ch->flags &=211211+ ~IEEE80211_CHAN_PASSIVE_SCAN;212212+ } else {213213+ if (ch->beacon_found)214214+ ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |215215+ IEEE80211_CHAN_PASSIVE_SCAN);216216+ }217217+ }204218 }219219+205220}206221207222/* Allows active scan scan on Ch 12 and 13 */···235208 u32 bandwidth = 0;236209 int r;237210238238- /* Force passive scan on Channels 12-13 */239211 sband = wiphy->bands[IEEE80211_BAND_2GHZ];240212241241- /* If no country IE has been received always enable active scan242242- * on these channels */213213+ /*214214+ * If no country IE has been received always enable active scan215215+ * on these channels. This is only done for specific regulatory SKUs216216+ */243217 if (setby != REGDOM_SET_BY_COUNTRY_IE) {244218 ch = &sband->channels[11]; /* CH 12 */245219 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)···251223 return;252224 }253225254254- /* If a country IE has been recieved check its rule for this226226+ /*227227+ * If a country IE has been recieved check its rule for this255228 * channel first before enabling active scan. The passive scan256256- * would have been enforced by the initial probe processing on257257- * our custom regulatory domain. */229229+ * would have been enforced by the initial processing of our230230+ * custom regulatory domain.231231+ */258232259233 ch = &sband->channels[11]; /* CH 12 */260234 r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule);···319289 case 0x63:320290 case 0x66:321291 case 0x67:322322- ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);292292+ ath9k_reg_apply_beaconing_flags(wiphy, setby);323293 break;324294 case 0x68:325325- ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);295295+ ath9k_reg_apply_beaconing_flags(wiphy, setby);326296 ath9k_reg_apply_active_scan_flags(wiphy, setby);327297 break;328298 }···401371}402372403373/* Returns the map of the EEPROM set RD to a country code */404404-static u16 ath9k_regd_get_default_country(struct ath_hw *ah)374374+static u16 ath9k_regd_get_default_country(u16 rd)405375{406406- u16 rd;407407-408408- rd = ath9k_regd_get_eepromRD(ah);409376 if (rd & COUNTRY_ERD_FLAG) {410377 struct country_code_to_enum_rd *country = NULL;411378 u16 cc = rd & ~COUNTRY_ERD_FLAG;···432405int ath9k_regd_init(struct ath_hw *ah)433406{434407 struct country_code_to_enum_rd *country = NULL;435435- int regdmn;408408+ u16 regdmn;436409437410 if (!ath9k_regd_is_eeprom_valid(ah)) {438411 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,···440413 return -EINVAL;441414 }442415443443- ah->regulatory.country_code = ath9k_regd_get_default_country(ah);416416+ regdmn = ath9k_regd_get_eepromRD(ah);417417+ ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);444418445419 if (ah->regulatory.country_code == CTRY_DEFAULT &&446446- ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)420420+ regdmn == CTRY_DEFAULT)447421 ah->regulatory.country_code = CTRY_UNITED_STATES;448422449423 if (ah->regulatory.country_code == CTRY_DEFAULT) {450450- regdmn = ath9k_regd_get_eepromRD(ah);451424 country = NULL;452425 } else {453426 country = ath9k_regd_find_country(ah->regulatory.country_code);···460433 regdmn = country->regDmnEnum;461434 }462435463463- ah->regulatory.current_rd_inuse = regdmn;464436 ah->regulatory.regpair = ath9k_get_regpair(regdmn);465437466438 if (!ah->regulatory.regpair) {···493467 u32 ctl = NO_CTL;494468495469 if (!ah->regulatory.regpair ||496496- (ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) {470470+ (ah->regulatory.country_code == CTRY_DEFAULT &&471471+ is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {497472 if (IS_CHAN_B(chan))498473 ctl = SD_NO_CTL | CTL_11B;499474 else if (IS_CHAN_G(chan))···507480 if (IS_CHAN_B(chan))508481 ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;509482 else if (IS_CHAN_G(chan))510510- ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G;483483+ ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;511484 else512485 ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;513486
···186186 % echo 0x00000FFO > /proc/net/ieee80211/debug_level187187188188 For a list of values you can assign to debug_level, you189189- can look at the bit mask values in <net/ieee80211.h>189189+ can look at the bit mask values in ieee80211.h190190191191 If you are not trying to debug or develop the libipw192192 component, you most likely want to say N here.
+11-1
drivers/net/wireless/ipw2x00/ipw2100.c
···16921692 u32 lock;16931693 u32 ord_len = sizeof(lock);1694169416951695- /* Quite if manually disabled. */16951695+ /* Age scan list entries found before suspend */16961696+ if (priv->suspend_time) {16971697+ ieee80211_networks_age(priv->ieee, priv->suspend_time);16981698+ priv->suspend_time = 0;16991699+ }17001700+17011701+ /* Quiet if manually disabled. */16961702 if (priv->status & STATUS_RF_KILL_SW) {16971703 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "16981704 "switch\n", priv->net_dev->name);···64216415 pci_disable_device(pci_dev);64226416 pci_set_power_state(pci_dev, PCI_D3hot);6423641764186418+ priv->suspend_at = get_seconds();64196419+64246420 mutex_unlock(&priv->action_mutex);6425642164266422 return 0;···64656457 /* Set the device back into the PRESENT state; this will also wake64666458 * the queue of needed */64676459 netif_device_attach(dev);64606460+64616461+ priv->suspend_time = get_seconds() - priv->suspend_at;6468646264696463 /* Bring the device back up */64706464 if (!(priv->status & STATUS_RF_KILL_SW))
+6-2
drivers/net/wireless/ipw2x00/ipw2100.h
···3939#include <linux/wireless.h>4040#include <net/iw_handler.h> // new driver API41414242-#include <net/ieee80211.h>4343-4442#ifdef CONFIG_IPW2100_MONITOR4543#include <net/ieee80211_radiotap.h>4644#endif47454846#include <linux/workqueue.h>4947#include <linux/mutex.h>4848+4949+#include "ieee80211.h"50505151struct ipw2100_priv;5252struct ipw2100_tx_packet;···590590 struct delayed_work scan_event_later;591591592592 int user_requested_scan;593593+594594+ /* Track time in suspend */595595+ unsigned long suspend_at;596596+ unsigned long suspend_time;593597594598 u32 interrupts;595599 int tx_interrupts;
+70-46
drivers/net/wireless/ipw2x00/ipw2200.c
···301301}302302303303/* 8-bit direct write (low 4K) */304304-#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))304304+static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs,305305+ u8 val)306306+{307307+ writeb(val, ipw->hw_base + ofs);308308+}305309306310/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */307311#define ipw_write8(ipw, ofs, val) do { \308308- IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \309309- _ipw_write8(ipw, ofs, val); \310310- } while (0)312312+ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \313313+ __LINE__, (u32)(ofs), (u32)(val)); \314314+ _ipw_write8(ipw, ofs, val); \315315+} while (0)311316312317/* 16-bit direct write (low 4K) */313313-#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))318318+static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs,319319+ u16 val)320320+{321321+ writew(val, ipw->hw_base + ofs);322322+}314323315324/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */316316-#define ipw_write16(ipw, ofs, val) \317317- IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \318318- _ipw_write16(ipw, ofs, val)325325+#define ipw_write16(ipw, ofs, val) do { \326326+ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \327327+ __LINE__, (u32)(ofs), (u32)(val)); \328328+ _ipw_write16(ipw, ofs, val); \329329+} while (0)319330320331/* 32-bit direct write (low 4K) */321321-#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))332332+static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs,333333+ u32 val)334334+{335335+ writel(val, ipw->hw_base + ofs);336336+}322337323338/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */324324-#define ipw_write32(ipw, ofs, val) \325325- IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \326326- _ipw_write32(ipw, ofs, val)339339+#define ipw_write32(ipw, ofs, val) do { \340340+ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \341341+ __LINE__, (u32)(ofs), (u32)(val)); \342342+ _ipw_write32(ipw, ofs, val); \343343+} while (0)327344328345/* 8-bit direct read (low 4K) */329329-#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))330330-331331-/* 8-bit direct read (low 4K), with debug wrapper */332332-static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)346346+static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs)333347{334334- IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs));335335- return _ipw_read8(ipw, ofs);348348+ return readb(ipw->hw_base + ofs);336349}337350338351/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */339339-#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)352352+#define ipw_read8(ipw, ofs) ({ \353353+ IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \354354+ (u32)(ofs)); \355355+ _ipw_read8(ipw, ofs); \356356+})340357341358/* 16-bit direct read (low 4K) */342342-#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))343343-344344-/* 16-bit direct read (low 4K), with debug wrapper */345345-static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)359359+static inline u16 _ipw_read16(struct ipw_priv *ipw, unsigned long ofs)346360{347347- IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs));348348- return _ipw_read16(ipw, ofs);361361+ return readw(ipw->hw_base + ofs);349362}350363351364/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */352352-#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)365365+#define ipw_read16(ipw, ofs) ({ \366366+ IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", __FILE__, __LINE__, \367367+ (u32)(ofs)); \368368+ _ipw_read16(ipw, ofs); \369369+})353370354371/* 32-bit direct read (low 4K) */355355-#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))356356-357357-/* 32-bit direct read (low 4K), with debug wrapper */358358-static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)372372+static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs)359373{360360- IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs));361361- return _ipw_read32(ipw, ofs);374374+ return readl(ipw->hw_base + ofs);362375}363376364377/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */365365-#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)378378+#define ipw_read32(ipw, ofs) ({ \379379+ IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \380380+ (u32)(ofs)); \381381+ _ipw_read32(ipw, ofs); \382382+})366383367367-/* multi-byte read (above 4K), with debug wrapper */368384static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);369369-static inline void __ipw_read_indirect(const char *f, int l,370370- struct ipw_priv *a, u32 b, u8 * c, int d)371371-{372372- IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b),373373- d);374374- _ipw_read_indirect(a, b, c, d);375375-}376376-377385/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */378378-#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)386386+#define ipw_read_indirect(a, b, c, d) ({ \387387+ IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \388388+ __LINE__, (u32)(b), (u32)(d)); \389389+ _ipw_read_indirect(a, b, c, d); \390390+})379391380392/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */381393static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,382394 int num);383383-#define ipw_write_indirect(a, b, c, d) \384384- IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \385385- _ipw_write_indirect(a, b, c, d)395395+#define ipw_write_indirect(a, b, c, d) do { \396396+ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \397397+ __LINE__, (u32)(b), (u32)(d)); \398398+ _ipw_write_indirect(a, b, c, d); \399399+} while (0)386400387401/* 32-bit indirect write (above 4K) */388402static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)···1123811224{1123911225 int rc, i, j;11240112261122711227+ /* Age scan list entries found before suspend */1122811228+ if (priv->suspend_time) {1122911229+ ieee80211_networks_age(priv->ieee, priv->suspend_time);1123011230+ priv->suspend_time = 0;1123111231+ }1123211232+1124111233 if (priv->status & STATUS_EXIT_PENDING)1124211234 return -EIO;1124311235···1184411824 pci_disable_device(pdev);1184511825 pci_set_power_state(pdev, pci_choose_state(pdev, state));11846118261182711827+ priv->suspend_at = get_seconds();1182811828+1184711829 return 0;1184811830}1184911831···1188011858 /* Set the device back into the PRESENT state; this will also wake1188111859 * the queue of needed */1188211860 netif_device_attach(dev);1186111861+1186211862+ priv->suspend_time = get_seconds() - priv->suspend_at;11883118631188411864 /* Bring the device back up */1188511865 queue_work(priv->workqueue, &priv->up);
+6-1
drivers/net/wireless/ipw2x00/ipw2200.h
···4949#include <asm/io.h>50505151#include <net/lib80211.h>5252-#include <net/ieee80211.h>5352#include <net/ieee80211_radiotap.h>54535554#define DRV_NAME "ipw2200"56555756#include <linux/workqueue.h>5757+5858+#include "ieee80211.h"58595960/* Authentication and Association States */6061enum connection_manager_assoc_states {···13461345 u8 adapter;1347134613481347 s8 tx_power;13481348+13491349+ /* Track time in suspend */13501350+ unsigned long suspend_at;13511351+ unsigned long suspend_time;1349135213501353#ifdef CONFIG_PM13511354 u32 pm_state[16];
···3535#include <linux/jiffies.h>36363737#include <net/lib80211.h>3838-#include <net/ieee80211.h>3938#include <linux/wireless.h>3939+4040+#include "ieee80211.h"40414142static const char *ieee80211_modes[] = {4243 "?", "a", "b", "ab", "g", "ag", "bg", "abg"4344};4545+4646+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)4747+{4848+ unsigned long end = jiffies;4949+5050+ if (end >= start)5151+ return jiffies_to_msecs(end - start);5252+5353+ return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);5454+}44554556#define MAX_CUSTOM_LEN 644657static char *ieee80211_translate_scan(struct ieee80211_device *ieee,···226215 iwe.cmd = IWEVCUSTOM;227216 p = custom;228217 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),229229- " Last beacon: %dms ago",230230- jiffies_to_msecs(jiffies - network->last_scanned));218218+ " Last beacon: %ums ago",219219+ elapsed_jiffies_msecs(network->last_scanned));231220 iwe.u.data.length = p - custom;232221 if (iwe.u.data.length)233222 start = iwe_stream_add_point(info, start, stop, &iwe, custom);···287276 time_after(network->last_scanned + ieee->scan_age, jiffies))288277 ev = ieee80211_translate_scan(ieee, ev, stop, network,289278 info);290290- else279279+ else {291280 IEEE80211_DEBUG_SCAN("Not showing network '%s ("292292- "%pM)' due to age (%dms).\n",281281+ "%pM)' due to age (%ums).\n",293282 print_ssid(ssid, network->ssid,294283 network->ssid_len),295284 network->bssid,296296- jiffies_to_msecs(jiffies -297297- network->298298- last_scanned));285285+ elapsed_jiffies_msecs(286286+ network->last_scanned));287287+ }299288 }300289301290 spin_unlock_irqrestore(&ieee->lock, flags);
+20-36
drivers/net/wireless/iwlwifi/Kconfig
···11config IWLWIFI22- bool "Intel Wireless Wifi"22+ tristate "Intel Wireless Wifi"33 depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL44- default y55-66-config IWLCORE77- tristate "Intel Wireless Wifi Core"88- depends on IWLWIFI94 select LIB8021155+ select FW_LOADER106 select MAC80211_LEDS if IWLWIFI_LEDS117 select LEDS_CLASS if IWLWIFI_LEDS128 select RFKILL if IWLWIFI_RFKILL99+ select MAC80211_LEDS if IWL3945_LEDS1010+ select LEDS_CLASS if IWL3945_LEDS13111412config IWLWIFI_LEDS1513 bool "Enable LED support in iwlagn driver"1616- depends on IWLCORE1414+ depends on IWLWIFI17151816config IWLWIFI_RFKILL1919- bool "Enable RF kill support in iwlagn driver"2020- depends on IWLCORE1717+ bool "Enable RF kill support in iwlagn and iwl3945 drivers"1818+ depends on IWLWIFI1919+2020+config IWLWIFI_SPECTRUM_MEASUREMENT2121+ bool "Enable Spectrum Measurement in iwlagn driver"2222+ depends on IWLWIFI2323+ ---help---2424+ This option will enable spectrum measurement for the iwlagn driver.21252226config IWLWIFI_DEBUG2327 bool "Enable full debugging output in iwlagn and iwl3945 drivers"2424- depends on IWLCORE2828+ depends on IWLWIFI2529 ---help---2630 This option will enable debug tracing output for the iwlwifi drivers2731···4945 any problems you may encounter.50465147config IWLWIFI_DEBUGFS5252- bool "Iwlwifi debugfs support"5353- depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS4848+ bool "iwlagn debugfs support"4949+ depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS5450 ---help---5551 Enable creation of debugfs files for the iwlwifi drivers.56525753config IWLAGN5858- tristate "Intel Wireless WiFi Next Gen AGN"5454+ tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"5955 depends on IWLWIFI6060- select FW_LOADER6161- select IWLCORE6256 ---help---6357 Select to build the driver supporting the:6458···7977 say M here and read <file:Documentation/kbuild/modules.txt>. The8078 module will be called iwlagn.ko.81798282-config IWLAGN_SPECTRUM_MEASUREMENT8383- bool "Enable Spectrum Measurement in iwlagn driver"8484- depends on IWLAGN8585- ---help---8686- This option will enable spectrum measurement for the iwlagn driver.8787-8888-config IWLAGN_LEDS8989- bool "Enable LEDS features in iwlagn driver"9090- depends on IWLAGN9191- select IWLWIFI_LEDS9292- ---help---9393- This option enables LEDS for the iwlagn drivers9494-95809681config IWL49659782 bool "Intel Wireless WiFi 4965AGN"···8798 This option enables support for Intel Wireless WiFi Link 4965AGN889989100config IWL50009090- bool "Intel Wireless WiFi 5000AGN"101101+ bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 100, 6000, and 6050 Series"91102 depends on IWLAGN92103 ---help---93104 This option enables support for Intel Wireless WiFi Link 5000AGN Family9410595106config IWL39459696- tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"107107+ tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"97108 depends on IWLWIFI9898- select FW_LOADER9999- select LIB80211100100- select MAC80211_LEDS if IWL3945_LEDS101101- select LEDS_CLASS if IWL3945_LEDS102102- select RFKILL if IWLWIFI_RFKILL103109 ---help---104110 Select to build the driver supporting the:105111···118134 module will be called iwl3945.ko.119135120136config IWL3945_SPECTRUM_MEASUREMENT121121- bool "Enable Spectrum Measurement in iwl3945 drivers"137137+ bool "Enable Spectrum Measurement in iwl3945 driver"122138 depends on IWL3945123139 ---help---124140 This option will enable spectrum measurement for the iwl3945 driver.
···5050#define EEPROM_SIZE 0x01005151#define BBP_BASE 0x00005252#define BBP_SIZE 0x00805353-#define RF_BASE 0x00005454-#define RF_SIZE 0x00145353+#define RF_BASE 0x00045454+#define RF_SIZE 0x001055555656/*5757 * Number of TX queues.
+6-13
drivers/net/wireless/rt2x00/rt73usb.c
···122122{123123 u32 reg;124124125125- if (!word)126126- return;127127-128125 mutex_lock(&rt2x00dev->csr_mutex);129126130127 /*···22382241 return 0;22392242}2240224322412241-#if 022422242-/*22432243- * Mac80211 demands get_tsf must be atomic.22442244- * This is not possible for rt73usb since all register access22452245- * functions require sleeping. Untill mac80211 no longer needs22462246- * get_tsf to be atomic, this function should be disabled.22472247- */22482244static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)22492245{22502246 struct rt2x00_dev *rt2x00dev = hw->priv;···2251226122522262 return tsf;22532263}22542254-#else22552255-#define rt73usb_get_tsf NULL22562256-#endif2257226422582265static const struct ieee80211_ops rt73usb_mac80211_ops = {22592266 .tx = rt2x00mac_tx,···23422355static struct usb_device_id rt73usb_device_table[] = {23432356 /* AboCom */23442357 { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },23582358+ /* Amigo */23592359+ { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },23602360+ { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },23452361 /* Askey */23462362 { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },23472363 /* ASUS */···23922402 { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },23932403 { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },23942404 /* Ralink */24052405+ { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },23952406 { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },23962407 { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },23972408 /* Qcom */···24092418 /* Planex */24102419 { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },24112420 { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },24212421+ /* ZyXEL */24222422+ { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) },24122423 { 0, }24132424};24142425
+2-2
drivers/net/wireless/rt2x00/rt73usb.h
···5050#define EEPROM_SIZE 0x01005151#define BBP_BASE 0x00005252#define BBP_SIZE 0x00805353-#define RF_BASE 0x00005454-#define RF_SIZE 0x00145353+#define RF_BASE 0x00045454+#define RF_SIZE 0x001055555656/*5757 * Number of TX queues.
+1-2
drivers/net/wireless/wavelan.c
···428142814282428242834283 /* Loop on all possible base addresses. */42844284- i = -1;42854285- while ((io[++i] != 0) && (i < ARRAY_SIZE(io))) {42844284+ for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) {42864285 struct net_device *dev = alloc_etherdev(sizeof(net_local));42874286 if (!dev)42884287 break;
+3-3
drivers/net/wireless/zd1211rw/zd_mac.c
···170170 goto disable_int;171171172172 r = zd_reg2alpha2(mac->regdomain, alpha2);173173- if (!r)174174- regulatory_hint(hw->wiphy, alpha2);173173+ if (r)174174+ goto disable_int;175175176176- r = 0;176176+ r = regulatory_hint(hw->wiphy, alpha2);177177disable_int:178178 zd_chip_disable_int(chip);179179out:
+5
include/linux/nl80211.h
···526526 * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)527527 * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute528528 * containing info as possible, see &enum nl80211_sta_info_txrate.529529+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)530530+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this531531+ * station)529532 */530533enum nl80211_sta_info {531534 __NL80211_STA_INFO_INVALID,···540537 NL80211_STA_INFO_PLINK_STATE,541538 NL80211_STA_INFO_SIGNAL,542539 NL80211_STA_INFO_TX_BITRATE,540540+ NL80211_STA_INFO_RX_PACKETS,541541+ NL80211_STA_INFO_TX_PACKETS,543542544543 /* keep last */545544 __NL80211_STA_INFO_AFTER_LAST,
+23-8
include/net/cfg80211.h
···178178 * @STATION_INFO_SIGNAL: @signal filled179179 * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled180180 * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)181181+ * @STATION_INFO_RX_PACKETS: @rx_packets filled182182+ * @STATION_INFO_TX_PACKETS: @tx_packets filled181183 */182184enum station_info_flags {183185 STATION_INFO_INACTIVE_TIME = 1<<0,···190188 STATION_INFO_PLINK_STATE = 1<<5,191189 STATION_INFO_SIGNAL = 1<<6,192190 STATION_INFO_TX_BITRATE = 1<<7,191191+ STATION_INFO_RX_PACKETS = 1<<8,192192+ STATION_INFO_TX_PACKETS = 1<<9,193193};194194195195/**···239235 * @plink_state: mesh peer link state240236 * @signal: signal strength of last received packet in dBm241237 * @txrate: current unicast bitrate to this station238238+ * @rx_packets: packets received from this station239239+ * @tx_packets: packets transmitted to this station242240 */243241struct station_info {244242 u32 filled;···252246 u8 plink_state;253247 s8 signal;254248 struct rate_info txrate;249249+ u32 rx_packets;250250+ u32 tx_packets;255251};256252257253/**···383375};384376385377/**386386- * struct regulatory_request - receipt of last regulatory request378378+ * struct regulatory_request - used to keep track of regulatory requests387379 *388388- * @wiphy: this is set if this request's initiator is380380+ * @wiphy_idx: this is set if this request's initiator is389381 * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This390382 * can be used by the wireless core to deal with conflicts391383 * and potentially inform users of which devices specifically···404396 * country IE405397 * @country_ie_env: lets us know if the AP is telling us we are outdoor,406398 * indoor, or if it doesn't matter399399+ * @list: used to insert into the reg_requests_list linked list407400 */408401struct regulatory_request {409409- struct wiphy *wiphy;402402+ int wiphy_idx;410403 enum reg_set_by initiator;411404 char alpha2[2];412405 bool intersect;413406 u32 country_ie_checksum;414407 enum environment_cap country_ie_env;408408+ struct list_head list;415409};416410417411struct ieee80211_freq_range {···535525 * @n_ssids: number of SSIDs536526 * @channels: channels to scan on.537527 * @n_channels: number of channels for each band528528+ * @ie: optional information element(s) to add into Probe Request or %NULL529529+ * @ie_len: length of ie in octets538530 * @wiphy: the wiphy this was for539531 * @ifidx: the interface index540532 */···545533 int n_ssids;546534 struct ieee80211_channel **channels;547535 u32 n_channels;536536+ u8 *ie;537537+ size_t ie_len;548538549539 /* internal */550540 struct wiphy *wiphy;···579565 * @information_elements: the information elements (Note that there580566 * is no guarantee that these are well-formed!)581567 * @len_information_elements: total length of the information elements582582- * @signal: signal strength value583583- * @signal_type: signal type568568+ * @signal: signal strength value (type depends on the wiphy's signal_type)584569 * @free_priv: function pointer to free private data585570 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes586571 */···594581 size_t len_information_elements;595582596583 s32 signal;597597- enum cfg80211_signal_type signal_type;598584599585 void (*free_priv)(struct cfg80211_bss *bss);600586 u8 priv[0] __attribute__((__aligned__(sizeof(void *))));···767755int cfg80211_wext_giwscan(struct net_device *dev,768756 struct iw_request_info *info,769757 struct iw_point *data, char *extra);758758+int cfg80211_wext_giwrange(struct net_device *dev,759759+ struct iw_request_info *info,760760+ struct iw_point *data, char *extra);770761771762/**772763 * cfg80211_scan_done - notify that scan finished···785770 *786771 * @wiphy: the wiphy reporting the BSS787772 * @bss: the found BSS773773+ * @signal: the signal strength, type depends on the wiphy's signal_type788774 * @gfp: context flags789775 *790776 * This informs cfg80211 that BSS information was found and···795779cfg80211_inform_bss_frame(struct wiphy *wiphy,796780 struct ieee80211_channel *channel,797781 struct ieee80211_mgmt *mgmt, size_t len,798798- s32 signal, enum cfg80211_signal_type sigtype,799799- gfp_t gfp);782782+ s32 signal, gfp_t gfp);800783801784struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,802785 struct ieee80211_channel *channel,
···10221022 return hw->queues;10231023}1024102410251025-static inline int ieee80211_num_queues(struct ieee80211_hw *hw)10261026-{10271027- return hw->queues + hw->ampdu_queues;10281028-}10291029-10301025static inline struct ieee80211_rate *10311026ieee80211_get_tx_rate(const struct ieee80211_hw *hw,10321027 const struct ieee80211_tx_info *c)···13241329 * because the hardware is turned off! Anything else is a bug!13251330 * Returns a negative error code which will be seen in userspace.13261331 *13321332+ * @sw_scan_start: Notifier function that is called just before a software scan13331333+ * is started. Can be NULL, if the driver doesn't need this notification.13341334+ *13351335+ * @sw_scan_complete: Notifier function that is called just after a software scan13361336+ * finished. Can be NULL, if the driver doesn't need this notification.13371337+ *13271338 * @get_stats: Return low-level statistics.13281339 * Returns zero if statistics are available.13291340 *···14091408 u32 iv32, u16 *phase1key);14101409 int (*hw_scan)(struct ieee80211_hw *hw,14111410 struct cfg80211_scan_request *req);14111411+ void (*sw_scan_start)(struct ieee80211_hw *hw);14121412+ void (*sw_scan_complete)(struct ieee80211_hw *hw);14121413 int (*get_stats)(struct ieee80211_hw *hw,14131414 struct ieee80211_low_level_stats *stats);14141415 void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,···19831980/* Rate control API */1984198119851982/**19831983+ * enum rate_control_changed - flags to indicate which parameter changed19841984+ *19851985+ * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have19861986+ * changed, rate control algorithm can update its internal state if needed.19871987+ */19881988+enum rate_control_changed {19891989+ IEEE80211_RC_HT_CHANGED = BIT(0)19901990+};19911991+19921992+/**19861993 * struct ieee80211_tx_rate_control - rate control information for/from RC algo19871994 *19881995 * @hw: The hardware the algorithm is invoked for.···20282015 void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);20292016 void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,20302017 struct ieee80211_sta *sta, void *priv_sta);20182018+ void (*rate_update)(void *priv, struct ieee80211_supported_band *sband,20192019+ struct ieee80211_sta *sta,20202020+ void *priv_sta, u32 changed);20312021 void (*free_sta)(void *priv, struct ieee80211_sta *sta,20322022 void *priv_sta);20332023
+15-2
include/net/wireless.h
···6969 * @band: band this channel belongs to.7070 * @max_antenna_gain: maximum antenna gain in dBi7171 * @max_power: maximum transmission power (in dBm)7272+ * @beacon_found: helper to regulatory code to indicate when a beacon7373+ * has been found on this channel. Use regulatory_hint_found_beacon()7474+ * to enable this, this is is useful only on 5 GHz band.7275 * @orig_mag: internal use7376 * @orig_mpwr: internal use7477 */···8380 u32 flags;8481 int max_antenna_gain;8582 int max_power;8383+ bool beacon_found;8684 u32 orig_flags;8785 int orig_mag, orig_mpwr;8886};···204200 * the regulatory_hint() API. This can be used by the driver205201 * on the reg_notifier() if it chooses to ignore future206202 * regulatory domain changes caused by other drivers.203203+ * @signal_type: signal type reported in &struct cfg80211_bss.207204 */208205struct wiphy {209206 /* assign these fields before you register the wiphy */···217212218213 bool custom_regulatory;219214 bool strict_regulatory;215215+216216+ enum cfg80211_signal_type signal_type;220217221218 int bss_priv_size;222219 u8 max_scan_ssids;···405398 * domain should be in or by providing a completely build regulatory domain.406399 * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried407400 * for a regulatory domain structure for the respective country.401401+ *402402+ * The wiphy must have been registered to cfg80211 prior to this call.403403+ * For cfg80211 drivers this means you must first use wiphy_register(),404404+ * for mac80211 drivers you must first use ieee80211_register_hw().405405+ *406406+ * Drivers should check the return value, its possible you can get407407+ * an -ENOMEM.408408 */409409-extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);409409+extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);410410411411/**412412 * regulatory_hint_11d - hints a country IE as a regulatory domain···429415extern void regulatory_hint_11d(struct wiphy *wiphy,430416 u8 *country_ie,431417 u8 country_ie_len);432432-433418/**434419 * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain435420 * @wiphy: the wireless device we want to process the regulatory domain on
···4949 u16 agg_size, u16 timeout)5050{5151 struct ieee80211_local *local = sdata->local;5252- struct ieee80211_if_sta *ifsta = &sdata->u.sta;5352 struct sk_buff *skb;5453 struct ieee80211_mgmt *mgmt;5554 u16 capab;···6869 if (sdata->vif.type == NL80211_IFTYPE_AP ||6970 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)7071 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);7171- else7272- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);7272+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)7373+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);73747475 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |7576 IEEE80211_STYPE_ACTION);···131132132133 state = &sta->ampdu_mlme.tid_state_tx[tid];133134134134- if (local->hw.ampdu_queues)135135- ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);135135+ if (local->hw.ampdu_queues) {136136+ if (initiator) {137137+ /*138138+ * Stop the AC queue to avoid issues where we send139139+ * unaggregated frames already before the delba.140140+ */141141+ ieee80211_stop_queue_by_reason(&local->hw,142142+ local->hw.queues + sta->tid_to_tx_q[tid],143143+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);144144+ }136145146146+ /*147147+ * Pretend the driver woke the queue, just in case148148+ * it disabled it before the session was stopped.149149+ */150150+ ieee80211_wake_queue(151151+ &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);152152+ }137153 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |138154 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);139155···158144 /* HW shall not deny going back to legacy */159145 if (WARN_ON(ret)) {160146 *state = HT_AGG_STATE_OPERATIONAL;161161- if (local->hw.ampdu_queues)162162- ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);163147 }164148165149 return ret;···201189 spin_unlock_bh(&sta->lock);202190}203191192192+static inline int ieee80211_ac_from_tid(int tid)193193+{194194+ return ieee802_1d_to_ac[tid & 7];195195+}196196+204197int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)205198{206199 struct ieee80211_local *local = hw_to_local(hw);207200 struct sta_info *sta;208201 struct ieee80211_sub_if_data *sdata;209209- u16 start_seq_num;210202 u8 *state;211211- int ret = 0;203203+ int i, qn = -1, ret = 0;204204+ u16 start_seq_num;212205213206 if (WARN_ON(!local->ops->ampdu_action))214207 return -EINVAL;···226209 ra, tid);227210#endif /* CONFIG_MAC80211_HT_DEBUG */228211212212+ if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {213213+#ifdef CONFIG_MAC80211_HT_DEBUG214214+ printk(KERN_DEBUG "rejecting on voice AC\n");215215+#endif216216+ return -EINVAL;217217+ }218218+229219 rcu_read_lock();230220231221 sta = sta_info_get(local, ra);···241217 printk(KERN_DEBUG "Could not find the station\n");242218#endif243219 ret = -ENOENT;244244- goto exit;220220+ goto unlock;245221 }246222247223 /*···254230 sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&255231 sta->sdata->vif.type != NL80211_IFTYPE_AP) {256232 ret = -EINVAL;257257- goto exit;233233+ goto unlock;258234 }259235260236 spin_lock_bh(&sta->lock);237237+238238+ sdata = sta->sdata;261239262240 /* we have tried too many times, receiver does not want A-MPDU */263241 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {···278252 goto err_unlock_sta;279253 }280254255255+ if (hw->ampdu_queues) {256256+ spin_lock(&local->queue_stop_reason_lock);257257+ /* reserve a new queue for this session */258258+ for (i = 0; i < local->hw.ampdu_queues; i++) {259259+ if (local->ampdu_ac_queue[i] < 0) {260260+ qn = i;261261+ local->ampdu_ac_queue[qn] =262262+ ieee80211_ac_from_tid(tid);263263+ break;264264+ }265265+ }266266+ spin_unlock(&local->queue_stop_reason_lock);267267+268268+ if (qn < 0) {269269+#ifdef CONFIG_MAC80211_HT_DEBUG270270+ printk(KERN_DEBUG "BA request denied - "271271+ "queue unavailable for tid %d\n", tid);272272+#endif /* CONFIG_MAC80211_HT_DEBUG */273273+ ret = -ENOSPC;274274+ goto err_unlock_sta;275275+ }276276+277277+ /*278278+ * If we successfully allocate the session, we can't have279279+ * anything going on on the queue this TID maps into, so280280+ * stop it for now. This is a "virtual" stop using the same281281+ * mechanism that drivers will use.282282+ *283283+ * XXX: queue up frames for this session in the sta_info284284+ * struct instead to avoid hitting all other STAs.285285+ */286286+ ieee80211_stop_queue_by_reason(287287+ &local->hw, hw->queues + qn,288288+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);289289+ }290290+281291 /* prepare A-MPDU MLME for Tx aggregation */282292 sta->ampdu_mlme.tid_tx[tid] =283293 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);···324262 tid);325263#endif326264 ret = -ENOMEM;327327- goto err_unlock_sta;265265+ goto err_return_queue;328266 }267267+329268 /* Tx timer */330269 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =331270 sta_addba_resp_timer_expired;···334271 (unsigned long)&sta->timer_to_tid[tid];335272 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);336273337337- if (hw->ampdu_queues) {338338- /* create a new queue for this aggregation */339339- ret = ieee80211_ht_agg_queue_add(local, sta, tid);340340-341341- /* case no queue is available to aggregation342342- * don't switch to aggregation */343343- if (ret) {344344-#ifdef CONFIG_MAC80211_HT_DEBUG345345- printk(KERN_DEBUG "BA request denied - "346346- "queue unavailable for tid %d\n", tid);347347-#endif /* CONFIG_MAC80211_HT_DEBUG */348348- goto err_unlock_queue;349349- }350350- }351351- sdata = sta->sdata;352352-353274 /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the354275 * call back right away, it must see that the flow has begun */355276 *state |= HT_ADDBA_REQUESTED_MSK;356277357357- /* This is slightly racy because the queue isn't stopped */358278 start_seq_num = sta->tid_seq[tid];359279360280 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,361281 &sta->sta, tid, &start_seq_num);362282363283 if (ret) {364364- /* No need to requeue the packets in the agg queue, since we365365- * held the tx lock: no packet could be enqueued to the newly366366- * allocated queue */367367- if (hw->ampdu_queues)368368- ieee80211_ht_agg_queue_remove(local, sta, tid, 0);369284#ifdef CONFIG_MAC80211_HT_DEBUG370285 printk(KERN_DEBUG "BA request denied - HW unavailable for"371286 " tid %d\n", tid);372287#endif /* CONFIG_MAC80211_HT_DEBUG */373288 *state = HT_AGG_STATE_IDLE;374374- goto err_unlock_queue;289289+ goto err_free;375290 }291291+ sta->tid_to_tx_q[tid] = qn;376292377377- /* Will put all the packets in the new SW queue */378378- if (hw->ampdu_queues)379379- ieee80211_requeue(local, ieee802_1d_to_ac[tid]);380293 spin_unlock_bh(&sta->lock);381294382295 /* send an addBA request */···360321 sta->ampdu_mlme.tid_tx[tid]->dialog_token =361322 sta->ampdu_mlme.dialog_token_allocator;362323 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;363363-364324365325 ieee80211_send_addba_request(sta->sdata, ra, tid,366326 sta->ampdu_mlme.tid_tx[tid]->dialog_token,···372334#ifdef CONFIG_MAC80211_HT_DEBUG373335 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);374336#endif375375- goto exit;337337+ goto unlock;376338377377-err_unlock_queue:339339+ err_free:378340 kfree(sta->ampdu_mlme.tid_tx[tid]);379341 sta->ampdu_mlme.tid_tx[tid] = NULL;380380- ret = -EBUSY;381381-err_unlock_sta:342342+ err_return_queue:343343+ if (qn >= 0) {344344+ /* We failed, so start queue again right away. */345345+ ieee80211_wake_queue_by_reason(hw, hw->queues + qn,346346+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);347347+ /* give queue back to pool */348348+ spin_lock(&local->queue_stop_reason_lock);349349+ local->ampdu_ac_queue[qn] = -1;350350+ spin_unlock(&local->queue_stop_reason_lock);351351+ }352352+ err_unlock_sta:382353 spin_unlock_bh(&sta->lock);383383-exit:354354+ unlock:384355 rcu_read_unlock();385356 return ret;386357}···422375 state = &sta->ampdu_mlme.tid_state_tx[tid];423376 spin_lock_bh(&sta->lock);424377425425- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {378378+ if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {426379#ifdef CONFIG_MAC80211_HT_DEBUG427380 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",428381 *state);···432385 return;433386 }434387435435- WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);388388+ if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))389389+ goto out;436390437391 *state |= HT_ADDBA_DRV_READY_MSK;438392···441393#ifdef CONFIG_MAC80211_HT_DEBUG442394 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);443395#endif444444- if (hw->ampdu_queues)445445- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);396396+ if (hw->ampdu_queues) {397397+ /*398398+ * Wake up this queue, we stopped it earlier,399399+ * this will in turn wake the entire AC.400400+ */401401+ ieee80211_wake_queue_by_reason(hw,402402+ hw->queues + sta->tid_to_tx_q[tid],403403+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);404404+ }446405 }406406+407407+ out:447408 spin_unlock_bh(&sta->lock);448409 rcu_read_unlock();449410}···542485 struct ieee80211_local *local = hw_to_local(hw);543486 struct sta_info *sta;544487 u8 *state;545545- int agg_queue;546488547489 if (tid >= STA_TID_NUM) {548490#ifdef CONFIG_MAC80211_HT_DEBUG···583527 ieee80211_send_delba(sta->sdata, ra, tid,584528 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);585529586586- if (hw->ampdu_queues) {587587- agg_queue = sta->tid_to_tx_q[tid];588588- ieee80211_ht_agg_queue_remove(local, sta, tid, 1);589589-590590- /* We just requeued the all the frames that were in the591591- * removed queue, and since we might miss a softirq we do592592- * netif_schedule_queue. ieee80211_wake_queue is not used593593- * here as this queue is not necessarily stopped594594- */595595- netif_schedule_queue(netdev_get_tx_queue(local->mdev,596596- agg_queue));597597- }598530 spin_lock_bh(&sta->lock);531531+532532+ if (*state & HT_AGG_STATE_INITIATOR_MSK &&533533+ hw->ampdu_queues) {534534+ /*535535+ * Wake up this queue, we stopped it earlier,536536+ * this will in turn wake the entire AC.537537+ */538538+ ieee80211_wake_queue_by_reason(hw,539539+ hw->queues + sta->tid_to_tx_q[tid],540540+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);541541+ }542542+599543 *state = HT_AGG_STATE_IDLE;600544 sta->ampdu_mlme.addba_req_num[tid] = 0;601545 kfree(sta->ampdu_mlme.tid_tx[tid]);···669613#endif /* CONFIG_MAC80211_HT_DEBUG */670614 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)671615 == WLAN_STATUS_SUCCESS) {672672- *state |= HT_ADDBA_RECEIVED_MSK;673673- sta->ampdu_mlme.addba_req_num[tid] = 0;616616+ u8 curstate = *state;674617675675- if (*state == HT_AGG_STATE_OPERATIONAL &&676676- local->hw.ampdu_queues)677677- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);618618+ *state |= HT_ADDBA_RECEIVED_MSK;619619+620620+ if (hw->ampdu_queues && *state != curstate &&621621+ *state == HT_AGG_STATE_OPERATIONAL) {622622+ /*623623+ * Wake up this queue, we stopped it earlier,624624+ * this will in turn wake the entire AC.625625+ */626626+ ieee80211_wake_queue_by_reason(hw,627627+ hw->queues + sta->tid_to_tx_q[tid],628628+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);629629+ }630630+ sta->ampdu_mlme.addba_req_num[tid] = 0;678631679632 if (local->ops->ampdu_action) {680633 (void)local->ops->ampdu_action(hw,
···236236 break;237237 case NL80211_IFTYPE_STATION:238238 case NL80211_IFTYPE_ADHOC:239239- sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;239239+ if (sdata->vif.type == NL80211_IFTYPE_STATION)240240+ sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;241241+ else242242+ sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET;240243 /* fall through */241244 default:242245 conf.vif = &sdata->vif;···324321 * yet be effective. Trigger execution of ieee80211_sta_work325322 * to fix this.326323 */327327- if (sdata->vif.type == NL80211_IFTYPE_STATION ||328328- sdata->vif.type == NL80211_IFTYPE_ADHOC) {329329- struct ieee80211_if_sta *ifsta = &sdata->u.sta;330330- queue_work(local->hw.workqueue, &ifsta->work);331331- }324324+ if (sdata->vif.type == NL80211_IFTYPE_STATION)325325+ queue_work(local->hw.workqueue, &sdata->u.mgd.work);326326+ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)327327+ queue_work(local->hw.workqueue, &sdata->u.ibss.work);332328333329 netif_tx_start_all_queues(dev);334330···454452 netif_addr_unlock_bh(local->mdev);455453 break;456454 case NL80211_IFTYPE_STATION:457457- case NL80211_IFTYPE_ADHOC:458455 /* Announce that we are leaving the network. */459459- if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED)456456+ if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED)460457 ieee80211_sta_deauthenticate(sdata,461458 WLAN_REASON_DEAUTH_LEAVING);462462-463463- memset(sdata->u.sta.bssid, 0, ETH_ALEN);464464- del_timer_sync(&sdata->u.sta.chswitch_timer);465465- del_timer_sync(&sdata->u.sta.timer);459459+ memset(sdata->u.mgd.bssid, 0, ETH_ALEN);460460+ del_timer_sync(&sdata->u.mgd.chswitch_timer);461461+ del_timer_sync(&sdata->u.mgd.timer);466462 /*467463 * If the timer fired while we waited for it, it will have468464 * requeued the work. Now the work will be running again···468468 * whether the interface is running, which, at this point,469469 * it no longer is.470470 */471471- cancel_work_sync(&sdata->u.sta.work);472472- cancel_work_sync(&sdata->u.sta.chswitch_work);471471+ cancel_work_sync(&sdata->u.mgd.work);472472+ cancel_work_sync(&sdata->u.mgd.chswitch_work);473473 /*474474 * When we get here, the interface is marked down.475475 * Call synchronize_rcu() to wait for the RX path···477477 * frames at this very time on another CPU.478478 */479479 synchronize_rcu();480480- skb_queue_purge(&sdata->u.sta.skb_queue);480480+ skb_queue_purge(&sdata->u.mgd.skb_queue);481481482482- sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |482482+ sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |483483 IEEE80211_STA_TKIP_WEP_USED);484484- kfree(sdata->u.sta.extra_ie);485485- sdata->u.sta.extra_ie = NULL;486486- sdata->u.sta.extra_ie_len = 0;484484+ kfree(sdata->u.mgd.extra_ie);485485+ sdata->u.mgd.extra_ie = NULL;486486+ sdata->u.mgd.extra_ie_len = 0;487487+ /* fall through */488488+ case NL80211_IFTYPE_ADHOC:489489+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {490490+ memset(sdata->u.ibss.bssid, 0, ETH_ALEN);491491+ del_timer_sync(&sdata->u.ibss.timer);492492+ cancel_work_sync(&sdata->u.ibss.work);493493+ synchronize_rcu();494494+ skb_queue_purge(&sdata->u.ibss.skb_queue);495495+ }487496 /* fall through */488497 case NL80211_IFTYPE_MESH_POINT:489498 if (ieee80211_vif_is_mesh(&sdata->vif)) {···638629 if (ieee80211_vif_is_mesh(&sdata->vif))639630 mesh_rmc_free(sdata);640631 break;641641- case NL80211_IFTYPE_STATION:642632 case NL80211_IFTYPE_ADHOC:643643- kfree(sdata->u.sta.extra_ie);644644- kfree(sdata->u.sta.assocreq_ies);645645- kfree(sdata->u.sta.assocresp_ies);646646- kfree_skb(sdata->u.sta.probe_resp);647647- kfree(sdata->u.sta.ie_probereq);648648- kfree(sdata->u.sta.ie_proberesp);649649- kfree(sdata->u.sta.ie_auth);650650- kfree(sdata->u.sta.ie_assocreq);651651- kfree(sdata->u.sta.ie_reassocreq);652652- kfree(sdata->u.sta.ie_deauth);653653- kfree(sdata->u.sta.ie_disassoc);633633+ kfree_skb(sdata->u.ibss.probe_resp);634634+ break;635635+ case NL80211_IFTYPE_STATION:636636+ kfree(sdata->u.mgd.extra_ie);637637+ kfree(sdata->u.mgd.assocreq_ies);638638+ kfree(sdata->u.mgd.assocresp_ies);639639+ kfree(sdata->u.mgd.ie_probereq);640640+ kfree(sdata->u.mgd.ie_proberesp);641641+ kfree(sdata->u.mgd.ie_auth);642642+ kfree(sdata->u.mgd.ie_assocreq);643643+ kfree(sdata->u.mgd.ie_reassocreq);644644+ kfree(sdata->u.mgd.ie_deauth);645645+ kfree(sdata->u.mgd.ie_disassoc);654646 break;655647 case NL80211_IFTYPE_WDS:656648 case NL80211_IFTYPE_AP_VLAN:···718708 INIT_LIST_HEAD(&sdata->u.ap.vlans);719709 break;720710 case NL80211_IFTYPE_STATION:721721- case NL80211_IFTYPE_ADHOC:722711 ieee80211_sta_setup_sdata(sdata);712712+ break;713713+ case NL80211_IFTYPE_ADHOC:714714+ ieee80211_ibss_setup_sdata(sdata);723715 break;724716 case NL80211_IFTYPE_MESH_POINT:725717 if (ieee80211_vif_is_mesh(&sdata->vif))···810798811799 memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);812800 SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));801801+ ndev->features |= NETIF_F_NETNS_LOCAL;813802814803 /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */815804 sdata = netdev_priv(ndev);
+1-1
net/mac80211/key.c
···400400 */401401402402 /* same here, the AP could be using QoS */403403- ap = sta_info_get(key->local, key->sdata->u.sta.bssid);403403+ ap = sta_info_get(key->local, key->sdata->u.mgd.bssid);404404 if (ap) {405405 if (test_sta_flags(ap, WLAN_STA_WME))406406 key->conf.flags |=
+18-6
net/mac80211/main.c
···169169170170 memset(&conf, 0, sizeof(conf));171171172172- if (sdata->vif.type == NL80211_IFTYPE_STATION ||173173- sdata->vif.type == NL80211_IFTYPE_ADHOC)174174- conf.bssid = sdata->u.sta.bssid;172172+ if (sdata->vif.type == NL80211_IFTYPE_STATION)173173+ conf.bssid = sdata->u.mgd.bssid;174174+ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)175175+ conf.bssid = sdata->u.ibss.bssid;175176 else if (sdata->vif.type == NL80211_IFTYPE_AP)176177 conf.bssid = sdata->dev->dev_addr;177178 else if (ieee80211_vif_is_mesh(&sdata->vif)) {···211210 !!rcu_dereference(sdata->u.ap.beacon);212211 break;213212 case NL80211_IFTYPE_ADHOC:214214- conf.enable_beacon = !!sdata->u.sta.probe_resp;213213+ conf.enable_beacon = !!sdata->u.ibss.probe_resp;215214 break;216215 case NL80211_IFTYPE_MESH_POINT:217216 conf.enable_beacon = true;···706705 const struct ieee80211_ops *ops)707706{708707 struct ieee80211_local *local;709709- int priv_size;708708+ int priv_size, i;710709 struct wiphy *wiphy;711710712711 /* Ensure 32-byte alignment of our private data and hw private data.···779778 ieee80211_dynamic_ps_disable_work);780779 setup_timer(&local->dynamic_ps_timer,781780 ieee80211_dynamic_ps_timer, (unsigned long) local);781781+782782+ for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++)783783+ local->ampdu_ac_queue[i] = -1;784784+ /* using an s8 won't work with more than that */785785+ BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127);782786783787 sta_info_init(local);784788···861855 /* mac80211 always supports monitor */862856 local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);863857858858+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)859859+ local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;860860+ else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)861861+ local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;862862+864863 result = wiphy_register(local->hw.wiphy);865864 if (result < 0)866865 goto fail_wiphy_register;···883872884873 mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),885874 "wmaster%d", ieee80211_master_setup,886886- ieee80211_num_queues(hw));875875+ hw->queues);887876 if (!mdev)888877 goto fail_mdev_alloc;889878···927916928917 memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);929918 SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));919919+ local->mdev->features |= NETIF_F_NETNS_LOCAL;930920931921 result = register_netdevice(local->mdev);932922 if (result < 0)
+439-1232
net/mac80211/mlme.c
···1515#include <linux/if_ether.h>1616#include <linux/skbuff.h>1717#include <linux/if_arp.h>1818-#include <linux/wireless.h>1919-#include <linux/random.h>2018#include <linux/etherdevice.h>2119#include <linux/rtnetlink.h>2222-#include <net/iw_handler.h>2320#include <net/mac80211.h>2421#include <asm/unaligned.h>2522···3235#define IEEE80211_MONITORING_INTERVAL (2 * HZ)3336#define IEEE80211_PROBE_INTERVAL (60 * HZ)3437#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)3535-#define IEEE80211_SCAN_INTERVAL (2 * HZ)3636-#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)3737-#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)3838-3939-#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)4040-#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)4141-4242-#define IEEE80211_IBSS_MAX_STA_ENTRIES 1284343-44384539/* utils */4640static int ecw2cw(int ecw)···8092 return count;8193}82948383-/* also used by mesh code */8484-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,8585- struct ieee802_11_elems *elems,8686- enum ieee80211_band band)8787-{8888- struct ieee80211_supported_band *sband;8989- struct ieee80211_rate *bitrates;9090- size_t num_rates;9191- u32 supp_rates;9292- int i, j;9393- sband = local->hw.wiphy->bands[band];9494-9595- if (!sband) {9696- WARN_ON(1);9797- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];9898- }9999-100100- bitrates = sband->bitrates;101101- num_rates = sband->n_bitrates;102102- supp_rates = 0;103103- for (i = 0; i < elems->supp_rates_len +104104- elems->ext_supp_rates_len; i++) {105105- u8 rate = 0;106106- int own_rate;107107- if (i < elems->supp_rates_len)108108- rate = elems->supp_rates[i];109109- else if (elems->ext_supp_rates)110110- rate = elems->ext_supp_rates111111- [i - elems->supp_rates_len];112112- own_rate = 5 * (rate & 0x7f);113113- for (j = 0; j < num_rates; j++)114114- if (bitrates[j].bitrate == own_rate)115115- supp_rates |= BIT(j);116116- }117117- return supp_rates;118118-}119119-12095/* frame sending functions */1219612297static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len)···88137 memcpy(skb_put(skb, ies_len), ies, ies_len);89138}901399191-/* also used by scanning code */9292-void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,9393- u8 *ssid, size_t ssid_len)140140+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)94141{9595- struct ieee80211_local *local = sdata->local;9696- struct ieee80211_supported_band *sband;9797- struct sk_buff *skb;9898- struct ieee80211_mgmt *mgmt;9999- u8 *pos, *supp_rates, *esupp_rates = NULL;100100- int i;101101-102102- skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +103103- sdata->u.sta.ie_probereq_len);104104- if (!skb) {105105- printk(KERN_DEBUG "%s: failed to allocate buffer for probe "106106- "request\n", sdata->dev->name);107107- return;108108- }109109- skb_reserve(skb, local->hw.extra_tx_headroom);110110-111111- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);112112- memset(mgmt, 0, 24);113113- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |114114- IEEE80211_STYPE_PROBE_REQ);115115- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);116116- if (dst) {117117- memcpy(mgmt->da, dst, ETH_ALEN);118118- memcpy(mgmt->bssid, dst, ETH_ALEN);119119- } else {120120- memset(mgmt->da, 0xff, ETH_ALEN);121121- memset(mgmt->bssid, 0xff, ETH_ALEN);122122- }123123- pos = skb_put(skb, 2 + ssid_len);124124- *pos++ = WLAN_EID_SSID;125125- *pos++ = ssid_len;126126- memcpy(pos, ssid, ssid_len);127127-128128- supp_rates = skb_put(skb, 2);129129- supp_rates[0] = WLAN_EID_SUPP_RATES;130130- supp_rates[1] = 0;131131- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];132132-133133- for (i = 0; i < sband->n_bitrates; i++) {134134- struct ieee80211_rate *rate = &sband->bitrates[i];135135- if (esupp_rates) {136136- pos = skb_put(skb, 1);137137- esupp_rates[1]++;138138- } else if (supp_rates[1] == 8) {139139- esupp_rates = skb_put(skb, 3);140140- esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;141141- esupp_rates[1] = 1;142142- pos = &esupp_rates[2];143143- } else {144144- pos = skb_put(skb, 1);145145- supp_rates[1]++;146146- }147147- *pos = rate->bitrate / 5;148148- }149149-150150- add_extra_ies(skb, sdata->u.sta.ie_probereq,151151- sdata->u.sta.ie_probereq_len);152152-153153- ieee80211_tx_skb(sdata, skb, 0);154154-}155155-156156-static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,157157- struct ieee80211_if_sta *ifsta,158158- int transaction, u8 *extra, size_t extra_len,159159- int encrypt)160160-{161161- struct ieee80211_local *local = sdata->local;162162- struct sk_buff *skb;163163- struct ieee80211_mgmt *mgmt;164164-165165- skb = dev_alloc_skb(local->hw.extra_tx_headroom +166166- sizeof(*mgmt) + 6 + extra_len +167167- sdata->u.sta.ie_auth_len);168168- if (!skb) {169169- printk(KERN_DEBUG "%s: failed to allocate buffer for auth "170170- "frame\n", sdata->dev->name);171171- return;172172- }173173- skb_reserve(skb, local->hw.extra_tx_headroom);174174-175175- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);176176- memset(mgmt, 0, 24 + 6);177177- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |178178- IEEE80211_STYPE_AUTH);179179- if (encrypt)180180- mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);181181- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);182182- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);183183- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);184184- mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);185185- mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);186186- ifsta->auth_transaction = transaction + 1;187187- mgmt->u.auth.status_code = cpu_to_le16(0);188188- if (extra)189189- memcpy(skb_put(skb, extra_len), extra, extra_len);190190- add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len);191191-192192- ieee80211_tx_skb(sdata, skb, encrypt);193193-}194194-195195-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,196196- struct ieee80211_if_sta *ifsta)197197-{142142+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;198143 struct ieee80211_local *local = sdata->local;199144 struct sk_buff *skb;200145 struct ieee80211_mgmt *mgmt;···103256 u32 rates = 0;104257 size_t e_ies_len;105258106106- if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {107107- e_ies = sdata->u.sta.ie_reassocreq;108108- e_ies_len = sdata->u.sta.ie_reassocreq_len;259259+ if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) {260260+ e_ies = sdata->u.mgd.ie_reassocreq;261261+ e_ies_len = sdata->u.mgd.ie_reassocreq_len;109262 } else {110110- e_ies = sdata->u.sta.ie_assocreq;111111- e_ies_len = sdata->u.sta.ie_assocreq_len;263263+ e_ies = sdata->u.mgd.ie_assocreq;264264+ e_ies_len = sdata->u.mgd.ie_assocreq_len;112265 }113266114267 skb = dev_alloc_skb(local->hw.extra_tx_headroom +115115- sizeof(*mgmt) + 200 + ifsta->extra_ie_len +116116- ifsta->ssid_len + e_ies_len);268268+ sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +269269+ ifmgd->ssid_len + e_ies_len);117270 if (!skb) {118271 printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "119272 "frame\n", sdata->dev->name);···123276124277 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];125278126126- capab = ifsta->capab;279279+ capab = ifmgd->capab;127280128281 if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {129282 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))···132285 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;133286 }134287135135- bss = ieee80211_rx_bss_get(local, ifsta->bssid,288288+ bss = ieee80211_rx_bss_get(local, ifmgd->bssid,136289 local->hw.conf.channel->center_freq,137137- ifsta->ssid, ifsta->ssid_len);290290+ ifmgd->ssid, ifmgd->ssid_len);138291 if (bss) {139292 if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)140293 capab |= WLAN_CAPABILITY_PRIVACY;···159312160313 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);161314 memset(mgmt, 0, 24);162162- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);315315+ memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);163316 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);164164- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);317317+ memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);165318166166- if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {319319+ if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {167320 skb_put(skb, 10);168321 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |169322 IEEE80211_STYPE_REASSOC_REQ);170323 mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);171324 mgmt->u.reassoc_req.listen_interval =172325 cpu_to_le16(local->hw.conf.listen_interval);173173- memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,326326+ memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid,174327 ETH_ALEN);175328 } else {176329 skb_put(skb, 4);···182335 }183336184337 /* SSID */185185- ies = pos = skb_put(skb, 2 + ifsta->ssid_len);338338+ ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);186339 *pos++ = WLAN_EID_SSID;187187- *pos++ = ifsta->ssid_len;188188- memcpy(pos, ifsta->ssid, ifsta->ssid_len);340340+ *pos++ = ifmgd->ssid_len;341341+ memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);189342190343 /* add all rates which were marked to be used above */191344 supp_rates_len = rates_len;···240393 }241394 }242395243243- if (ifsta->extra_ie) {244244- pos = skb_put(skb, ifsta->extra_ie_len);245245- memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);396396+ if (ifmgd->extra_ie) {397397+ pos = skb_put(skb, ifmgd->extra_ie_len);398398+ memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);246399 }247400248248- if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {401401+ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {249402 pos = skb_put(skb, 9);250403 *pos++ = WLAN_EID_VENDOR_SPECIFIC;251404 *pos++ = 7; /* len */···265418 * mode (11a/b/g) if any one of these ciphers is266419 * configured as pairwise.267420 */268268- if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&421421+ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&269422 sband->ht_cap.ht_supported &&270423 (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&271424 ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&272272- (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) {425425+ (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) {273426 struct ieee80211_ht_info *ht_info =274427 (struct ieee80211_ht_info *)(ht_ie + 2);275428 u16 cap = sband->ht_cap.cap;···306459307460 add_extra_ies(skb, e_ies, e_ies_len);308461309309- kfree(ifsta->assocreq_ies);310310- ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;311311- ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);312312- if (ifsta->assocreq_ies)313313- memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);462462+ kfree(ifmgd->assocreq_ies);463463+ ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies;464464+ ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL);465465+ if (ifmgd->assocreq_ies)466466+ memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len);314467315468 ieee80211_tx_skb(sdata, skb, 0);316469}···320473 u16 stype, u16 reason)321474{322475 struct ieee80211_local *local = sdata->local;323323- struct ieee80211_if_sta *ifsta = &sdata->u.sta;476476+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;324477 struct sk_buff *skb;325478 struct ieee80211_mgmt *mgmt;326479 u8 *ies;327480 size_t ies_len;328481329482 if (stype == IEEE80211_STYPE_DEAUTH) {330330- ies = sdata->u.sta.ie_deauth;331331- ies_len = sdata->u.sta.ie_deauth_len;483483+ ies = sdata->u.mgd.ie_deauth;484484+ ies_len = sdata->u.mgd.ie_deauth_len;332485 } else {333333- ies = sdata->u.sta.ie_disassoc;334334- ies_len = sdata->u.sta.ie_disassoc_len;486486+ ies = sdata->u.mgd.ie_disassoc;487487+ ies_len = sdata->u.mgd.ie_disassoc_len;335488 }336489337490 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) +···345498346499 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);347500 memset(mgmt, 0, 24);348348- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);501501+ memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);349502 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);350350- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);503503+ memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);351504 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);352505 skb_put(skb, 2);353506 /* u.deauth.reason_code == u.disassoc.reason_code */···355508356509 add_extra_ies(skb, ies, ies_len);357510358358- ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);511511+ ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);359512}360513361514void ieee80211_send_pspoll(struct ieee80211_local *local,362515 struct ieee80211_sub_if_data *sdata)363516{364364- struct ieee80211_if_sta *ifsta = &sdata->u.sta;517517+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;365518 struct ieee80211_pspoll *pspoll;366519 struct sk_buff *skb;367520 u16 fc;···378531 memset(pspoll, 0, sizeof(*pspoll));379532 fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;380533 pspoll->frame_control = cpu_to_le16(fc);381381- pspoll->aid = cpu_to_le16(ifsta->aid);534534+ pspoll->aid = cpu_to_le16(ifmgd->aid);382535383536 /* aid in PS-Poll has its two MSBs each set to 1 */384537 pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);385538386386- memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN);539539+ memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);387540 memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);388541389542 ieee80211_tx_skb(sdata, skb, 0);390390-391391- return;392543}393544394545/* MLME */395395-static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,396396- const size_t supp_rates_len,397397- const u8 *supp_rates)398398-{399399- struct ieee80211_local *local = sdata->local;400400- int i, have_higher_than_11mbit = 0;401401-402402- /* cf. IEEE 802.11 9.2.12 */403403- for (i = 0; i < supp_rates_len; i++)404404- if ((supp_rates[i] & 0x7f) * 5 > 110)405405- have_higher_than_11mbit = 1;406406-407407- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&408408- have_higher_than_11mbit)409409- sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;410410- else411411- sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;412412-413413- ieee80211_set_wmm_default(sdata);414414-}415415-416546static void ieee80211_sta_wmm_params(struct ieee80211_local *local,417417- struct ieee80211_if_sta *ifsta,547547+ struct ieee80211_if_managed *ifmgd,418548 u8 *wmm_param, size_t wmm_param_len)419549{420550 struct ieee80211_tx_queue_params params;···399575 int count;400576 u8 *pos;401577402402- if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))578578+ if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))403579 return;404580405581 if (!wmm_param)···408584 if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)409585 return;410586 count = wmm_param[6] & 0x0f;411411- if (count == ifsta->wmm_last_param_set)587587+ if (count == ifmgd->wmm_last_param_set)412588 return;413413- ifsta->wmm_last_param_set = count;589589+ ifmgd->wmm_last_param_set = count;414590415591 pos = wmm_param + 8;416592 left = wmm_param_len - 8;···495671{496672 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;497673#ifdef CONFIG_MAC80211_VERBOSE_DEBUG498498- struct ieee80211_if_sta *ifsta = &sdata->u.sta;674674+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;499675#endif500676 u32 changed = 0;501677 bool use_protection;···518694 printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",519695 sdata->dev->name,520696 use_protection ? "enabled" : "disabled",521521- ifsta->bssid);697697+ ifmgd->bssid);522698 }523699#endif524700 bss_conf->use_cts_prot = use_protection;···532708 " (BSSID=%pM)\n",533709 sdata->dev->name,534710 use_short_preamble ? "short" : "long",535535- ifsta->bssid);711711+ ifmgd->bssid);536712 }537713#endif538714 bss_conf->use_short_preamble = use_short_preamble;···546722 " (BSSID=%pM)\n",547723 sdata->dev->name,548724 use_short_slot ? "short" : "long",549549- ifsta->bssid);725725+ ifmgd->bssid);550726 }551727#endif552728 bss_conf->use_short_slot = use_short_slot;···556732 return changed;557733}558734559559-static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata,560560- struct ieee80211_if_sta *ifsta)735735+static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)561736{562737 union iwreq_data wrqu;738738+563739 memset(&wrqu, 0, sizeof(wrqu));564564- if (ifsta->flags & IEEE80211_STA_ASSOCIATED)565565- memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);740740+ if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)741741+ memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);566742 wrqu.ap_addr.sa_family = ARPHRD_ETHER;567743 wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);568744}569745570570-static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,571571- struct ieee80211_if_sta *ifsta)746746+static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)572747{748748+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;573749 char *buf;574750 size_t len;575751 int i;576752 union iwreq_data wrqu;577753578578- if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)754754+ if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)579755 return;580756581581- buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +582582- ifsta->assocresp_ies_len), GFP_KERNEL);757757+ buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +758758+ ifmgd->assocresp_ies_len), GFP_KERNEL);583759 if (!buf)584760 return;585761586762 len = sprintf(buf, "ASSOCINFO(");587587- if (ifsta->assocreq_ies) {763763+ if (ifmgd->assocreq_ies) {588764 len += sprintf(buf + len, "ReqIEs=");589589- for (i = 0; i < ifsta->assocreq_ies_len; i++) {765765+ for (i = 0; i < ifmgd->assocreq_ies_len; i++) {590766 len += sprintf(buf + len, "%02x",591591- ifsta->assocreq_ies[i]);767767+ ifmgd->assocreq_ies[i]);592768 }593769 }594594- if (ifsta->assocresp_ies) {595595- if (ifsta->assocreq_ies)770770+ if (ifmgd->assocresp_ies) {771771+ if (ifmgd->assocreq_ies)596772 len += sprintf(buf + len, " ");597773 len += sprintf(buf + len, "RespIEs=");598598- for (i = 0; i < ifsta->assocresp_ies_len; i++) {774774+ for (i = 0; i < ifmgd->assocresp_ies_len; i++) {599775 len += sprintf(buf + len, "%02x",600600- ifsta->assocresp_ies[i]);776776+ ifmgd->assocresp_ies[i]);601777 }602778 }603779 len += sprintf(buf + len, ")");604780605781 if (len > IW_CUSTOM_MAX) {606782 len = sprintf(buf, "ASSOCRESPIE=");607607- for (i = 0; i < ifsta->assocresp_ies_len; i++) {783783+ for (i = 0; i < ifmgd->assocresp_ies_len; i++) {608784 len += sprintf(buf + len, "%02x",609609- ifsta->assocresp_ies[i]);785785+ ifmgd->assocresp_ies[i]);610786 }611787 }612788···621797622798623799static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,624624- struct ieee80211_if_sta *ifsta,625800 u32 bss_info_changed)626801{802802+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;627803 struct ieee80211_local *local = sdata->local;628804 struct ieee80211_conf *conf = &local_to_hw(local)->conf;629805630806 struct ieee80211_bss *bss;631807632808 bss_info_changed |= BSS_CHANGED_ASSOC;633633- ifsta->flags |= IEEE80211_STA_ASSOCIATED;809809+ ifmgd->flags |= IEEE80211_STA_ASSOCIATED;634810635635- bss = ieee80211_rx_bss_get(local, ifsta->bssid,811811+ bss = ieee80211_rx_bss_get(local, ifmgd->bssid,636812 conf->channel->center_freq,637637- ifsta->ssid, ifsta->ssid_len);813813+ ifmgd->ssid, ifmgd->ssid_len);638814 if (bss) {639815 /* set timing information */640816 sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;···647823 ieee80211_rx_bss_put(local, bss);648824 }649825650650- ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;651651- memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);652652- ieee80211_sta_send_associnfo(sdata, ifsta);826826+ ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;827827+ memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);828828+ ieee80211_sta_send_associnfo(sdata);653829654654- ifsta->last_probe = jiffies;830830+ ifmgd->last_probe = jiffies;655831 ieee80211_led_assoc(local, 1);656832657833 sdata->vif.bss_conf.assoc = 1;···680856 netif_tx_start_all_queues(sdata->dev);681857 netif_carrier_on(sdata->dev);682858683683- ieee80211_sta_send_apinfo(sdata, ifsta);859859+ ieee80211_sta_send_apinfo(sdata);684860}685861686686-static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,687687- struct ieee80211_if_sta *ifsta)862862+static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)688863{689689- ifsta->direct_probe_tries++;690690- if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {864864+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;865865+866866+ ifmgd->direct_probe_tries++;867867+ if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {691868 printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",692692- sdata->dev->name, ifsta->bssid);693693- ifsta->state = IEEE80211_STA_MLME_DISABLED;694694- ieee80211_sta_send_apinfo(sdata, ifsta);869869+ sdata->dev->name, ifmgd->bssid);870870+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;871871+ ieee80211_sta_send_apinfo(sdata);695872696873 /*697874 * Most likely AP is not in the range so remove the698875 * bss information associated to the AP699876 */700700- ieee80211_rx_bss_remove(sdata, ifsta->bssid,877877+ ieee80211_rx_bss_remove(sdata, ifmgd->bssid,701878 sdata->local->hw.conf.channel->center_freq,702702- ifsta->ssid, ifsta->ssid_len);879879+ ifmgd->ssid, ifmgd->ssid_len);703880 return;704881 }705882706883 printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",707707- sdata->dev->name, ifsta->bssid,708708- ifsta->direct_probe_tries);884884+ sdata->dev->name, ifmgd->bssid,885885+ ifmgd->direct_probe_tries);709886710710- ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;887887+ ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;711888712712- set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request);889889+ set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request);713890714891 /* Direct probe is sent to broadcast address as some APs715892 * will not answer to direct packet in unassociated state.716893 */717894 ieee80211_send_probe_req(sdata, NULL,718718- ifsta->ssid, ifsta->ssid_len);895895+ ifmgd->ssid, ifmgd->ssid_len, NULL, 0);719896720720- mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);897897+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);721898}722899723900724724-static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,725725- struct ieee80211_if_sta *ifsta)901901+static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)726902{727727- ifsta->auth_tries++;728728- if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {903903+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;904904+905905+ ifmgd->auth_tries++;906906+ if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {729907 printk(KERN_DEBUG "%s: authentication with AP %pM"730908 " timed out\n",731731- sdata->dev->name, ifsta->bssid);732732- ifsta->state = IEEE80211_STA_MLME_DISABLED;733733- ieee80211_sta_send_apinfo(sdata, ifsta);734734- ieee80211_rx_bss_remove(sdata, ifsta->bssid,909909+ sdata->dev->name, ifmgd->bssid);910910+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;911911+ ieee80211_sta_send_apinfo(sdata);912912+ ieee80211_rx_bss_remove(sdata, ifmgd->bssid,735913 sdata->local->hw.conf.channel->center_freq,736736- ifsta->ssid, ifsta->ssid_len);914914+ ifmgd->ssid, ifmgd->ssid_len);737915 return;738916 }739917740740- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;918918+ ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;741919 printk(KERN_DEBUG "%s: authenticate with AP %pM\n",742742- sdata->dev->name, ifsta->bssid);920920+ sdata->dev->name, ifmgd->bssid);743921744744- ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);922922+ ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0,923923+ ifmgd->bssid, 0);924924+ ifmgd->auth_transaction = 2;745925746746- mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);926926+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);747927}748928749929/*···755927 * if self disconnected or a reason code from the AP.756928 */757929static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,758758- struct ieee80211_if_sta *ifsta, bool deauth,759759- bool self_disconnected, u16 reason)930930+ bool deauth, bool self_disconnected,931931+ u16 reason)760932{933933+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;761934 struct ieee80211_local *local = sdata->local;762935 struct sta_info *sta;763936 u32 changed = 0, config_changed = 0;764937765938 rcu_read_lock();766939767767- sta = sta_info_get(local, ifsta->bssid);940940+ sta = sta_info_get(local, ifmgd->bssid);768941 if (!sta) {769942 rcu_read_unlock();770943 return;771944 }772945773946 if (deauth) {774774- ifsta->direct_probe_tries = 0;775775- ifsta->auth_tries = 0;947947+ ifmgd->direct_probe_tries = 0;948948+ ifmgd->auth_tries = 0;776949 }777777- ifsta->assoc_scan_tries = 0;778778- ifsta->assoc_tries = 0;950950+ ifmgd->assoc_scan_tries = 0;951951+ ifmgd->assoc_tries = 0;779952780953 netif_tx_stop_all_queues(sdata->dev);781954 netif_carrier_off(sdata->dev);···792963 IEEE80211_STYPE_DISASSOC, reason);793964 }794965795795- ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;966966+ ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;796967 changed |= ieee80211_reset_erp_info(sdata);797968798969 ieee80211_led_assoc(local, 0);799970 changed |= BSS_CHANGED_ASSOC;800971 sdata->vif.bss_conf.assoc = false;801972802802- ieee80211_sta_send_apinfo(sdata, ifsta);973973+ ieee80211_sta_send_apinfo(sdata);803974804975 if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {805805- ifsta->state = IEEE80211_STA_MLME_DISABLED;806806- ieee80211_rx_bss_remove(sdata, ifsta->bssid,976976+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;977977+ ieee80211_rx_bss_remove(sdata, ifmgd->bssid,807978 sdata->local->hw.conf.channel->center_freq,808808- ifsta->ssid, ifsta->ssid_len);979979+ ifmgd->ssid, ifmgd->ssid_len);809980 }810981811982 rcu_read_unlock();···8289998291000 rcu_read_lock();8301001831831- sta = sta_info_get(local, ifsta->bssid);10021002+ sta = sta_info_get(local, ifmgd->bssid);8321003 if (!sta) {8331004 rcu_read_unlock();8341005 return;···8491020 return 1;8501021}8511022852852-static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,853853- struct ieee80211_if_sta *ifsta)10231023+static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)8541024{10251025+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;8551026 struct ieee80211_local *local = sdata->local;8561027 struct ieee80211_bss *bss;8571028 int bss_privacy;8581029 int wep_privacy;8591030 int privacy_invoked;8601031861861- if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))10321032+ if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL))8621033 return 0;8631034864864- bss = ieee80211_rx_bss_get(local, ifsta->bssid,10351035+ bss = ieee80211_rx_bss_get(local, ifmgd->bssid,8651036 local->hw.conf.channel->center_freq,866866- ifsta->ssid, ifsta->ssid_len);10371037+ ifmgd->ssid, ifmgd->ssid_len);8671038 if (!bss)8681039 return 0;86910408701041 bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);8711042 wep_privacy = !!ieee80211_sta_wep_configured(sdata);872872- privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);10431043+ privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);87310448741045 ieee80211_rx_bss_put(local, bss);8751046···8791050 return 1;8801051}8811052882882-static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,883883- struct ieee80211_if_sta *ifsta)10531053+static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)8841054{885885- ifsta->assoc_tries++;886886- if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {10551055+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;10561056+10571057+ ifmgd->assoc_tries++;10581058+ if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {8871059 printk(KERN_DEBUG "%s: association with AP %pM"8881060 " timed out\n",889889- sdata->dev->name, ifsta->bssid);890890- ifsta->state = IEEE80211_STA_MLME_DISABLED;891891- ieee80211_sta_send_apinfo(sdata, ifsta);892892- ieee80211_rx_bss_remove(sdata, ifsta->bssid,10611061+ sdata->dev->name, ifmgd->bssid);10621062+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;10631063+ ieee80211_sta_send_apinfo(sdata);10641064+ ieee80211_rx_bss_remove(sdata, ifmgd->bssid,8931065 sdata->local->hw.conf.channel->center_freq,894894- ifsta->ssid, ifsta->ssid_len);10661066+ ifmgd->ssid, ifmgd->ssid_len);8951067 return;8961068 }8971069898898- ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;10701070+ ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;8991071 printk(KERN_DEBUG "%s: associate with AP %pM\n",900900- sdata->dev->name, ifsta->bssid);901901- if (ieee80211_privacy_mismatch(sdata, ifsta)) {10721072+ sdata->dev->name, ifmgd->bssid);10731073+ if (ieee80211_privacy_mismatch(sdata)) {9021074 printk(KERN_DEBUG "%s: mismatch in privacy configuration and "9031075 "mixed-cell disabled - abort association\n", sdata->dev->name);904904- ifsta->state = IEEE80211_STA_MLME_DISABLED;10761076+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;9051077 return;9061078 }9071079908908- ieee80211_send_assoc(sdata, ifsta);10801080+ ieee80211_send_assoc(sdata);9091081910910- mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);10821082+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);9111083}91210849131085914914-static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,915915- struct ieee80211_if_sta *ifsta)10861086+static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)9161087{10881088+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;9171089 struct ieee80211_local *local = sdata->local;9181090 struct sta_info *sta;9191091 int disassoc;···9241094 * for better APs. */9251095 /* TODO: remove expired BSSes */9261096927927- ifsta->state = IEEE80211_STA_MLME_ASSOCIATED;10971097+ ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED;92810989291099 rcu_read_lock();9301100931931- sta = sta_info_get(local, ifsta->bssid);11011101+ sta = sta_info_get(local, ifmgd->bssid);9321102 if (!sta) {9331103 printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",934934- sdata->dev->name, ifsta->bssid);11041104+ sdata->dev->name, ifmgd->bssid);9351105 disassoc = 1;9361106 } else {9371107 disassoc = 0;9381108 if (time_after(jiffies,9391109 sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {940940- if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {11101110+ if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {9411111 printk(KERN_DEBUG "%s: No ProbeResp from "9421112 "current AP %pM - assume out of "9431113 "range\n",944944- sdata->dev->name, ifsta->bssid);11141114+ sdata->dev->name, ifmgd->bssid);9451115 disassoc = 1;9461116 } else947947- ieee80211_send_probe_req(sdata, ifsta->bssid,948948- ifsta->ssid,949949- ifsta->ssid_len);950950- ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;11171117+ ieee80211_send_probe_req(sdata, ifmgd->bssid,11181118+ ifmgd->ssid,11191119+ ifmgd->ssid_len,11201120+ NULL, 0);11211121+ ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL;9511122 } else {952952- ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;953953- if (time_after(jiffies, ifsta->last_probe +11231123+ ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;11241124+ if (time_after(jiffies, ifmgd->last_probe +9541125 IEEE80211_PROBE_INTERVAL)) {955955- ifsta->last_probe = jiffies;956956- ieee80211_send_probe_req(sdata, ifsta->bssid,957957- ifsta->ssid,958958- ifsta->ssid_len);11261126+ ifmgd->last_probe = jiffies;11271127+ ieee80211_send_probe_req(sdata, ifmgd->bssid,11281128+ ifmgd->ssid,11291129+ ifmgd->ssid_len,11301130+ NULL, 0);9591131 }9601132 }9611133 }···9651133 rcu_read_unlock();96611349671135 if (disassoc)968968- ieee80211_set_disassoc(sdata, ifsta, true, true,11361136+ ieee80211_set_disassoc(sdata, true, true,9691137 WLAN_REASON_PREV_AUTH_NOT_VALID);9701138 else971971- mod_timer(&ifsta->timer, jiffies +11391139+ mod_timer(&ifmgd->timer, jiffies +9721140 IEEE80211_MONITORING_INTERVAL);9731141}97411429751143976976-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,977977- struct ieee80211_if_sta *ifsta)11441144+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)9781145{11461146+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;11471147+9791148 printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);980980- ifsta->flags |= IEEE80211_STA_AUTHENTICATED;981981- ieee80211_associate(sdata, ifsta);11491149+ ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;11501150+ ieee80211_associate(sdata);9821151}983115298411539851154static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,986986- struct ieee80211_if_sta *ifsta,9871155 struct ieee80211_mgmt *mgmt,9881156 size_t len)9891157{···9941162 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);9951163 if (!elems.challenge)9961164 return;997997- ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2,998998- elems.challenge_len + 2, 1);999999-}10001000-10011001-static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,10021002- struct ieee80211_if_sta *ifsta,10031003- struct ieee80211_mgmt *mgmt,10041004- size_t len)10051005-{10061006- u16 auth_alg, auth_transaction, status_code;10071007-10081008- if (len < 24 + 6)10091009- return;10101010-10111011- auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);10121012- auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);10131013- status_code = le16_to_cpu(mgmt->u.auth.status_code);10141014-10151015- /*10161016- * IEEE 802.11 standard does not require authentication in IBSS10171017- * networks and most implementations do not seem to use it.10181018- * However, try to reply to authentication attempts if someone10191019- * has actually implemented this.10201020- */10211021- if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)10221022- ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);11651165+ ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg,11661166+ elems.challenge - 2, elems.challenge_len + 2,11671167+ sdata->u.mgd.bssid, 1);11681168+ sdata->u.mgd.auth_transaction = 4;10231169}1024117010251171static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,10261026- struct ieee80211_if_sta *ifsta,10271172 struct ieee80211_mgmt *mgmt,10281173 size_t len)10291174{11751175+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;10301176 u16 auth_alg, auth_transaction, status_code;1031117710321032- if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE)11781178+ if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE)10331179 return;1034118010351181 if (len < 24 + 6)10361182 return;1037118310381038- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)11841184+ if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)10391185 return;1040118610411041- if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)11871187+ if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)10421188 return;1043118910441190 auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);10451191 auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);10461192 status_code = le16_to_cpu(mgmt->u.auth.status_code);1047119310481048- if (auth_alg != ifsta->auth_alg ||10491049- auth_transaction != ifsta->auth_transaction)11941194+ if (auth_alg != ifmgd->auth_alg ||11951195+ auth_transaction != ifmgd->auth_transaction)10501196 return;1051119710521198 if (status_code != WLAN_STATUS_SUCCESS) {···10331223 const int num_algs = ARRAY_SIZE(algs);10341224 int i, pos;10351225 algs[0] = algs[1] = algs[2] = 0xff;10361036- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)12261226+ if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)10371227 algs[0] = WLAN_AUTH_OPEN;10381038- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)12281228+ if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)10391229 algs[1] = WLAN_AUTH_SHARED_KEY;10401040- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)12301230+ if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)10411231 algs[2] = WLAN_AUTH_LEAP;10421042- if (ifsta->auth_alg == WLAN_AUTH_OPEN)12321232+ if (ifmgd->auth_alg == WLAN_AUTH_OPEN)10431233 pos = 0;10441044- else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)12341234+ else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY)10451235 pos = 1;10461236 else10471237 pos = 2;···10491239 pos++;10501240 if (pos >= num_algs)10511241 pos = 0;10521052- if (algs[pos] == ifsta->auth_alg ||12421242+ if (algs[pos] == ifmgd->auth_alg ||10531243 algs[pos] == 0xff)10541244 continue;10551245 if (algs[pos] == WLAN_AUTH_SHARED_KEY &&10561246 !ieee80211_sta_wep_configured(sdata))10571247 continue;10581058- ifsta->auth_alg = algs[pos];12481248+ ifmgd->auth_alg = algs[pos];10591249 break;10601250 }10611251 }10621252 return;10631253 }1064125410651065- switch (ifsta->auth_alg) {12551255+ switch (ifmgd->auth_alg) {10661256 case WLAN_AUTH_OPEN:10671257 case WLAN_AUTH_LEAP:10681068- ieee80211_auth_completed(sdata, ifsta);12581258+ ieee80211_auth_completed(sdata);10691259 break;10701260 case WLAN_AUTH_SHARED_KEY:10711071- if (ifsta->auth_transaction == 4)10721072- ieee80211_auth_completed(sdata, ifsta);12611261+ if (ifmgd->auth_transaction == 4)12621262+ ieee80211_auth_completed(sdata);10731263 else10741074- ieee80211_auth_challenge(sdata, ifsta, mgmt, len);12641264+ ieee80211_auth_challenge(sdata, mgmt, len);10751265 break;10761266 }10771267}107812681079126910801270static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,10811081- struct ieee80211_if_sta *ifsta,10821271 struct ieee80211_mgmt *mgmt,10831272 size_t len)10841273{12741274+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;10851275 u16 reason_code;1086127610871277 if (len < 24 + 2)10881278 return;1089127910901090- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))12801280+ if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))10911281 return;1092128210931283 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);1094128410951095- if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)12851285+ if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED)10961286 printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",10971287 sdata->dev->name, reason_code);1098128810991099- if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||11001100- ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||11011101- ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {11021102- ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;11031103- mod_timer(&ifsta->timer, jiffies +12891289+ if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||12901290+ ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE ||12911291+ ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {12921292+ ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;12931293+ mod_timer(&ifmgd->timer, jiffies +11041294 IEEE80211_RETRY_AUTH_INTERVAL);11051295 }1106129611071107- ieee80211_set_disassoc(sdata, ifsta, true, false, 0);11081108- ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED;12971297+ ieee80211_set_disassoc(sdata, true, false, 0);12981298+ ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;11091299}111013001111130111121302static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,11131113- struct ieee80211_if_sta *ifsta,11141303 struct ieee80211_mgmt *mgmt,11151304 size_t len)11161305{13061306+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;11171307 u16 reason_code;1118130811191309 if (len < 24 + 2)11201310 return;1121131111221122- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))13121312+ if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))11231313 return;1124131411251315 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);1126131611271127- if (ifsta->flags & IEEE80211_STA_ASSOCIATED)13171317+ if (ifmgd->flags & IEEE80211_STA_ASSOCIATED)11281318 printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",11291319 sdata->dev->name, reason_code);1130132011311131- if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {11321132- ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;11331133- mod_timer(&ifsta->timer, jiffies +13211321+ if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {13221322+ ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;13231323+ mod_timer(&ifmgd->timer, jiffies +11341324 IEEE80211_RETRY_AUTH_INTERVAL);11351325 }1136132611371137- ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);13271327+ ieee80211_set_disassoc(sdata, false, false, reason_code);11381328}113913291140133011411331static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,11421142- struct ieee80211_if_sta *ifsta,11431332 struct ieee80211_mgmt *mgmt,11441333 size_t len,11451334 int reassoc)11461335{13361336+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;11471337 struct ieee80211_local *local = sdata->local;11481338 struct ieee80211_supported_band *sband;11491339 struct sta_info *sta;···11601350 /* AssocResp and ReassocResp have identical structure, so process both11611351 * of them in this function. */1162135211631163- if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE)13531353+ if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)11641354 return;1165135511661356 if (len < 24 + 6)11671357 return;1168135811691169- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)13591359+ if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)11701360 return;1171136111721362 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);···11911381 "comeback duration %u TU (%u ms)\n",11921382 sdata->dev->name, tu, ms);11931383 if (ms > IEEE80211_ASSOC_TIMEOUT)11941194- mod_timer(&ifsta->timer,13841384+ mod_timer(&ifmgd->timer,11951385 jiffies + msecs_to_jiffies(ms));11961386 return;11971387 }···12021392 /* if this was a reassociation, ensure we try a "full"12031393 * association next time. This works around some broken APs12041394 * which do not correctly reject reassociation requests. */12051205- ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;13951395+ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;12061396 return;12071397 }12081398···12181408 }1219140912201410 printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);12211221- ifsta->aid = aid;12221222- ifsta->ap_capab = capab_info;14111411+ ifmgd->aid = aid;14121412+ ifmgd->ap_capab = capab_info;1223141312241224- kfree(ifsta->assocresp_ies);12251225- ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);12261226- ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL);12271227- if (ifsta->assocresp_ies)12281228- memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);14141414+ kfree(ifmgd->assocresp_ies);14151415+ ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt);14161416+ ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL);14171417+ if (ifmgd->assocresp_ies)14181418+ memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len);1229141912301420 rcu_read_lock();1231142112321422 /* Add STA entry for the AP */12331233- sta = sta_info_get(local, ifsta->bssid);14231423+ sta = sta_info_get(local, ifmgd->bssid);12341424 if (!sta) {12351425 newsta = true;1236142612371237- sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);14271427+ sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC);12381428 if (!sta) {12391429 printk(KERN_DEBUG "%s: failed to alloc STA entry for"12401430 " the AP\n", sdata->dev->name);···1315150513161506 rate_control_rate_init(sta);1317150713181318- if (ifsta->flags & IEEE80211_STA_MFP_ENABLED)15081508+ if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)13191509 set_sta_flags(sta, WLAN_STA_MFP);1320151013211511 if (elems.wmm_param)···13341524 rcu_read_unlock();1335152513361526 if (elems.wmm_param)13371337- ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,15271527+ ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,13381528 elems.wmm_param_len);1339152913401530 if (elems.ht_info_elem && elems.wmm_param &&13411341- (ifsta->flags & IEEE80211_STA_WMM_ENABLED))15311531+ (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&15321532+ !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))13421533 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,13431534 ap_ht_cap_flags);13441535···13471536 * ieee80211_set_associated() will tell the driver */13481537 bss_conf->aid = aid;13491538 bss_conf->assoc_capability = capab_info;13501350- ieee80211_set_associated(sdata, ifsta, changed);15391539+ ieee80211_set_associated(sdata, changed);1351154013521352- ieee80211_associated(sdata, ifsta);15411541+ ieee80211_associated(sdata);13531542}1354154313551355-13561356-static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,13571357- struct ieee80211_if_sta *ifsta,13581358- const u8 *bssid, const int beacon_int,13591359- const int freq,13601360- const size_t supp_rates_len,13611361- const u8 *supp_rates,13621362- const u16 capability)13631363-{13641364- struct ieee80211_local *local = sdata->local;13651365- int res = 0, rates, i, j;13661366- struct sk_buff *skb;13671367- struct ieee80211_mgmt *mgmt;13681368- u8 *pos;13691369- struct ieee80211_supported_band *sband;13701370- union iwreq_data wrqu;13711371-13721372- if (local->ops->reset_tsf) {13731373- /* Reset own TSF to allow time synchronization work. */13741374- local->ops->reset_tsf(local_to_hw(local));13751375- }13761376-13771377- if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&13781378- memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0)13791379- return res;13801380-13811381- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +13821382- sdata->u.sta.ie_proberesp_len);13831383- if (!skb) {13841384- printk(KERN_DEBUG "%s: failed to allocate buffer for probe "13851385- "response\n", sdata->dev->name);13861386- return -ENOMEM;13871387- }13881388-13891389- if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {13901390- /* Remove possible STA entries from other IBSS networks. */13911391- sta_info_flush_delayed(sdata);13921392- }13931393-13941394- memcpy(ifsta->bssid, bssid, ETH_ALEN);13951395- res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);13961396- if (res)13971397- return res;13981398-13991399- local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;14001400-14011401- sdata->drop_unencrypted = capability &14021402- WLAN_CAPABILITY_PRIVACY ? 1 : 0;14031403-14041404- res = ieee80211_set_freq(sdata, freq);14051405-14061406- if (res)14071407- return res;14081408-14091409- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];14101410-14111411- /* Build IBSS probe response */14121412-14131413- skb_reserve(skb, local->hw.extra_tx_headroom);14141414-14151415- mgmt = (struct ieee80211_mgmt *)14161416- skb_put(skb, 24 + sizeof(mgmt->u.beacon));14171417- memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));14181418- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |14191419- IEEE80211_STYPE_PROBE_RESP);14201420- memset(mgmt->da, 0xff, ETH_ALEN);14211421- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);14221422- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);14231423- mgmt->u.beacon.beacon_int =14241424- cpu_to_le16(local->hw.conf.beacon_int);14251425- mgmt->u.beacon.capab_info = cpu_to_le16(capability);14261426-14271427- pos = skb_put(skb, 2 + ifsta->ssid_len);14281428- *pos++ = WLAN_EID_SSID;14291429- *pos++ = ifsta->ssid_len;14301430- memcpy(pos, ifsta->ssid, ifsta->ssid_len);14311431-14321432- rates = supp_rates_len;14331433- if (rates > 8)14341434- rates = 8;14351435- pos = skb_put(skb, 2 + rates);14361436- *pos++ = WLAN_EID_SUPP_RATES;14371437- *pos++ = rates;14381438- memcpy(pos, supp_rates, rates);14391439-14401440- if (sband->band == IEEE80211_BAND_2GHZ) {14411441- pos = skb_put(skb, 2 + 1);14421442- *pos++ = WLAN_EID_DS_PARAMS;14431443- *pos++ = 1;14441444- *pos++ = ieee80211_frequency_to_channel(freq);14451445- }14461446-14471447- pos = skb_put(skb, 2 + 2);14481448- *pos++ = WLAN_EID_IBSS_PARAMS;14491449- *pos++ = 2;14501450- /* FIX: set ATIM window based on scan results */14511451- *pos++ = 0;14521452- *pos++ = 0;14531453-14541454- if (supp_rates_len > 8) {14551455- rates = supp_rates_len - 8;14561456- pos = skb_put(skb, 2 + rates);14571457- *pos++ = WLAN_EID_EXT_SUPP_RATES;14581458- *pos++ = rates;14591459- memcpy(pos, &supp_rates[8], rates);14601460- }14611461-14621462- add_extra_ies(skb, sdata->u.sta.ie_proberesp,14631463- sdata->u.sta.ie_proberesp_len);14641464-14651465- ifsta->probe_resp = skb;14661466-14671467- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |14681468- IEEE80211_IFCC_BEACON_ENABLED);14691469-14701470-14711471- rates = 0;14721472- for (i = 0; i < supp_rates_len; i++) {14731473- int bitrate = (supp_rates[i] & 0x7f) * 5;14741474- for (j = 0; j < sband->n_bitrates; j++)14751475- if (sband->bitrates[j].bitrate == bitrate)14761476- rates |= BIT(j);14771477- }14781478- ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;14791479-14801480- ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);14811481-14821482- ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;14831483- ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;14841484- mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);14851485-14861486- ieee80211_led_assoc(local, true);14871487-14881488- memset(&wrqu, 0, sizeof(wrqu));14891489- memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);14901490- wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);14911491-14921492- return res;14931493-}14941494-14951495-static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,14961496- struct ieee80211_if_sta *ifsta,14971497- struct ieee80211_bss *bss)14981498-{14991499- return __ieee80211_sta_join_ibss(sdata, ifsta,15001500- bss->cbss.bssid,15011501- bss->cbss.beacon_interval,15021502- bss->cbss.channel->center_freq,15031503- bss->supp_rates_len, bss->supp_rates,15041504- bss->cbss.capability);15051505-}1506154415071545static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,15081546 struct ieee80211_mgmt *mgmt,···13631703 struct ieee80211_local *local = sdata->local;13641704 int freq;13651705 struct ieee80211_bss *bss;13661366- struct sta_info *sta;13671706 struct ieee80211_channel *channel;13681368- u64 beacon_timestamp, rx_timestamp;13691369- u32 supp_rates = 0;13701370- enum ieee80211_band band = rx_status->band;1371170713721708 if (elems->ds_params && elems->ds_params_len == 1)13731709 freq = ieee80211_channel_to_frequency(elems->ds_params[0]);···13751719 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)13761720 return;1377172113781378- if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&13791379- memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {13801380- supp_rates = ieee80211_sta_get_rates(local, elems, band);13811381-13821382- rcu_read_lock();13831383-13841384- sta = sta_info_get(local, mgmt->sa);13851385- if (sta) {13861386- u32 prev_rates;13871387-13881388- prev_rates = sta->sta.supp_rates[band];13891389- /* make sure mandatory rates are always added */13901390- sta->sta.supp_rates[band] = supp_rates |13911391- ieee80211_mandatory_rates(local, band);13921392-13931393-#ifdef CONFIG_MAC80211_IBSS_DEBUG13941394- if (sta->sta.supp_rates[band] != prev_rates)13951395- printk(KERN_DEBUG "%s: updated supp_rates set "13961396- "for %pM based on beacon info (0x%llx | "13971397- "0x%llx -> 0x%llx)\n",13981398- sdata->dev->name,13991399- sta->sta.addr,14001400- (unsigned long long) prev_rates,14011401- (unsigned long long) supp_rates,14021402- (unsigned long long) sta->sta.supp_rates[band]);14031403-#endif14041404- } else {14051405- ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);14061406- }14071407-14081408- rcu_read_unlock();14091409- }14101410-14111722 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,14121723 channel, beacon);14131724 if (!bss)14141725 return;1415172614161727 if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&14171417- (memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0)) {17281728+ (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {14181729 struct ieee80211_channel_sw_ie *sw_elem =14191730 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;14201731 ieee80211_process_chanswitch(sdata, sw_elem, bss);14211732 }1422173314231423- /* was just updated in ieee80211_bss_info_update */14241424- beacon_timestamp = bss->cbss.tsf;14251425-14261426- if (sdata->vif.type != NL80211_IFTYPE_ADHOC)14271427- goto put_bss;14281428-14291429- /* check if we need to merge IBSS */14301430-14311431- /* merge only on beacons (???) */14321432- if (!beacon)14331433- goto put_bss;14341434-14351435- /* we use a fixed BSSID */14361436- if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)14371437- goto put_bss;14381438-14391439- /* not an IBSS */14401440- if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))14411441- goto put_bss;14421442-14431443- /* different channel */14441444- if (bss->cbss.channel != local->oper_channel)14451445- goto put_bss;14461446-14471447- /* different SSID */14481448- if (elems->ssid_len != sdata->u.sta.ssid_len ||14491449- memcmp(elems->ssid, sdata->u.sta.ssid,14501450- sdata->u.sta.ssid_len))14511451- goto put_bss;14521452-14531453- if (rx_status->flag & RX_FLAG_TSFT) {14541454- /*14551455- * For correct IBSS merging we need mactime; since mactime is14561456- * defined as the time the first data symbol of the frame hits14571457- * the PHY, and the timestamp of the beacon is defined as "the14581458- * time that the data symbol containing the first bit of the14591459- * timestamp is transmitted to the PHY plus the transmitting14601460- * STA's delays through its local PHY from the MAC-PHY14611461- * interface to its interface with the WM" (802.11 11.1.2)14621462- * - equals the time this bit arrives at the receiver - we have14631463- * to take into account the offset between the two.14641464- *14651465- * E.g. at 1 MBit that means mactime is 192 usec earlier14661466- * (=24 bytes * 8 usecs/byte) than the beacon timestamp.14671467- */14681468- int rate;14691469-14701470- if (rx_status->flag & RX_FLAG_HT)14711471- rate = 65; /* TODO: HT rates */14721472- else14731473- rate = local->hw.wiphy->bands[band]->14741474- bitrates[rx_status->rate_idx].bitrate;14751475-14761476- rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);14771477- } else if (local && local->ops && local->ops->get_tsf)14781478- /* second best option: get current TSF */14791479- rx_timestamp = local->ops->get_tsf(local_to_hw(local));14801480- else14811481- /* can't merge without knowing the TSF */14821482- rx_timestamp = -1LLU;14831483-14841484-#ifdef CONFIG_MAC80211_IBSS_DEBUG14851485- printk(KERN_DEBUG "RX beacon SA=%pM BSSID="14861486- "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",14871487- mgmt->sa, mgmt->bssid,14881488- (unsigned long long)rx_timestamp,14891489- (unsigned long long)beacon_timestamp,14901490- (unsigned long long)(rx_timestamp - beacon_timestamp),14911491- jiffies);14921492-#endif14931493-14941494- if (beacon_timestamp > rx_timestamp) {14951495-#ifdef CONFIG_MAC80211_IBSS_DEBUG14961496- printk(KERN_DEBUG "%s: beacon TSF higher than "14971497- "local TSF - IBSS merge with BSSID %pM\n",14981498- sdata->dev->name, mgmt->bssid);14991499-#endif15001500- ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);15011501- ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);15021502- }15031503-15041504- put_bss:15051734 ieee80211_rx_bss_put(local, bss);15061735}15071736···13981857{13991858 size_t baselen;14001859 struct ieee802_11_elems elems;14011401- struct ieee80211_if_sta *ifsta = &sdata->u.sta;1402186014031861 if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))14041862 return; /* ignore ProbeResp to foreign address */···1413187314141874 /* direct probe may be part of the association flow */14151875 if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,14161416- &ifsta->request)) {18761876+ &sdata->u.mgd.request)) {14171877 printk(KERN_DEBUG "%s direct probe responded\n",14181878 sdata->dev->name);14191419- ieee80211_authenticate(sdata, ifsta);18791879+ ieee80211_authenticate(sdata);14201880 }14211881}14221422-1423188214241883static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,14251884 struct ieee80211_mgmt *mgmt,14261885 size_t len,14271886 struct ieee80211_rx_status *rx_status)14281887{14291429- struct ieee80211_if_sta *ifsta;18881888+ struct ieee80211_if_managed *ifmgd;14301889 size_t baselen;14311890 struct ieee802_11_elems elems;14321891 struct ieee80211_local *local = sdata->local;···1444190514451906 if (sdata->vif.type != NL80211_IFTYPE_STATION)14461907 return;14471447- ifsta = &sdata->u.sta;1448190814491449- if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) ||14501450- memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)19091909+ ifmgd = &sdata->u.mgd;19101910+19111911+ if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||19121912+ memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)14511913 return;1452191414531915 if (rx_status->freq != local->hw.conf.channel->center_freq)14541916 return;1455191714561456- ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,19181918+ ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,14571919 elems.wmm_param_len);1458192014591921 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK &&14601922 local->hw.conf.flags & IEEE80211_CONF_PS) {14611461- directed_tim = ieee80211_check_tim(&elems, ifsta->aid);19231923+ directed_tim = ieee80211_check_tim(&elems, ifmgd->aid);1462192414631925 if (directed_tim) {14641926 if (local->hw.conf.dynamic_ps_timeout > 0) {···14941954 erp_valid, erp_value);149519551496195614971497- if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {19571957+ if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&19581958+ !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) {14981959 struct sta_info *sta;14991960 struct ieee80211_supported_band *sband;15001961 u16 ap_ht_cap_flags;1501196215021963 rcu_read_lock();1503196415041504- sta = sta_info_get(local, ifsta->bssid);19651965+ sta = sta_info_get(local, ifmgd->bssid);15051966 if (!sta) {15061967 rcu_read_unlock();15071968 return;···15381997 ieee80211_bss_info_change_notify(sdata, changed);15391998}1540199915411541-15421542-static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,15431543- struct ieee80211_if_sta *ifsta,15441544- struct ieee80211_mgmt *mgmt,15451545- size_t len)20002000+ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,20012001+ struct sk_buff *skb,20022002+ struct ieee80211_rx_status *rx_status)15462003{15472004 struct ieee80211_local *local = sdata->local;15481548- int tx_last_beacon;15491549- struct sk_buff *skb;15501550- struct ieee80211_mgmt *resp;15511551- u8 *pos, *end;15521552-15531553- if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||15541554- len < 24 + 2 || !ifsta->probe_resp)15551555- return;15561556-15571557- if (local->ops->tx_last_beacon)15581558- tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));15591559- else15601560- tx_last_beacon = 1;15611561-15621562-#ifdef CONFIG_MAC80211_IBSS_DEBUG15631563- printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"15641564- " (tx_last_beacon=%d)\n",15651565- sdata->dev->name, mgmt->sa, mgmt->da,15661566- mgmt->bssid, tx_last_beacon);15671567-#endif /* CONFIG_MAC80211_IBSS_DEBUG */15681568-15691569- if (!tx_last_beacon)15701570- return;15711571-15721572- if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 &&15731573- memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)15741574- return;15751575-15761576- end = ((u8 *) mgmt) + len;15771577- pos = mgmt->u.probe_req.variable;15781578- if (pos[0] != WLAN_EID_SSID ||15791579- pos + 2 + pos[1] > end) {15801580-#ifdef CONFIG_MAC80211_IBSS_DEBUG15811581- printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "15821582- "from %pM\n",15831583- sdata->dev->name, mgmt->sa);15841584-#endif15851585- return;15861586- }15871587- if (pos[1] != 0 &&15881588- (pos[1] != ifsta->ssid_len ||15891589- memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) {15901590- /* Ignore ProbeReq for foreign SSID */15911591- return;15921592- }15931593-15941594- /* Reply with ProbeResp */15951595- skb = skb_copy(ifsta->probe_resp, GFP_KERNEL);15961596- if (!skb)15971597- return;15981598-15991599- resp = (struct ieee80211_mgmt *) skb->data;16001600- memcpy(resp->da, mgmt->sa, ETH_ALEN);16011601-#ifdef CONFIG_MAC80211_IBSS_DEBUG16021602- printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",16031603- sdata->dev->name, resp->da);16041604-#endif /* CONFIG_MAC80211_IBSS_DEBUG */16051605- ieee80211_tx_skb(sdata, skb, 0);16061606-}16071607-16081608-void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,16091609- struct ieee80211_rx_status *rx_status)16101610-{16111611- struct ieee80211_local *local = sdata->local;16121612- struct ieee80211_if_sta *ifsta;16132005 struct ieee80211_mgmt *mgmt;16142006 u16 fc;1615200716162008 if (skb->len < 24)16171617- goto fail;16181618-16191619- ifsta = &sdata->u.sta;20092009+ return RX_DROP_MONITOR;1620201016212011 mgmt = (struct ieee80211_mgmt *) skb->data;16222012 fc = le16_to_cpu(mgmt->frame_control);···15622090 case IEEE80211_STYPE_REASSOC_RESP:15632091 case IEEE80211_STYPE_DEAUTH:15642092 case IEEE80211_STYPE_DISASSOC:15651565- skb_queue_tail(&ifsta->skb_queue, skb);15661566- queue_work(local->hw.workqueue, &ifsta->work);15671567- return;20932093+ skb_queue_tail(&sdata->u.mgd.skb_queue, skb);20942094+ queue_work(local->hw.workqueue, &sdata->u.mgd.work);20952095+ return RX_QUEUED;15682096 }1569209715701570- fail:15711571- kfree_skb(skb);20982098+ return RX_DROP_MONITOR;15722099}1573210015742101static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,15752102 struct sk_buff *skb)15762103{15772104 struct ieee80211_rx_status *rx_status;15781578- struct ieee80211_if_sta *ifsta;15792105 struct ieee80211_mgmt *mgmt;15802106 u16 fc;15811581-15821582- ifsta = &sdata->u.sta;1583210715842108 rx_status = (struct ieee80211_rx_status *) skb->cb;15852109 mgmt = (struct ieee80211_mgmt *) skb->data;15862110 fc = le16_to_cpu(mgmt->frame_control);1587211115881588- if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {15891589- switch (fc & IEEE80211_FCTL_STYPE) {15901590- case IEEE80211_STYPE_PROBE_REQ:15911591- ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt,15921592- skb->len);15931593- break;15941594- case IEEE80211_STYPE_PROBE_RESP:15951595- ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,15961596- rx_status);15971597- break;15981598- case IEEE80211_STYPE_BEACON:15991599- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,16001600- rx_status);16011601- break;16021602- case IEEE80211_STYPE_AUTH:16031603- ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt,16041604- skb->len);16051605- break;16061606- }16071607- } else { /* NL80211_IFTYPE_STATION */16081608- switch (fc & IEEE80211_FCTL_STYPE) {16091609- case IEEE80211_STYPE_PROBE_RESP:16101610- ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,16111611- rx_status);16121612- break;16131613- case IEEE80211_STYPE_BEACON:16141614- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,16151615- rx_status);16161616- break;16171617- case IEEE80211_STYPE_AUTH:16181618- ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);16191619- break;16201620- case IEEE80211_STYPE_ASSOC_RESP:16211621- ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,16221622- skb->len, 0);16231623- break;16241624- case IEEE80211_STYPE_REASSOC_RESP:16251625- ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,16261626- skb->len, 1);16271627- break;16281628- case IEEE80211_STYPE_DEAUTH:16291629- ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);16301630- break;16311631- case IEEE80211_STYPE_DISASSOC:16321632- ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt,16331633- skb->len);16341634- break;16351635- }21122112+ switch (fc & IEEE80211_FCTL_STYPE) {21132113+ case IEEE80211_STYPE_PROBE_RESP:21142114+ ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,21152115+ rx_status);21162116+ break;21172117+ case IEEE80211_STYPE_BEACON:21182118+ ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,21192119+ rx_status);21202120+ break;21212121+ case IEEE80211_STYPE_AUTH:21222122+ ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);21232123+ break;21242124+ case IEEE80211_STYPE_ASSOC_RESP:21252125+ ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0);21262126+ break;21272127+ case IEEE80211_STYPE_REASSOC_RESP:21282128+ ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1);21292129+ break;21302130+ case IEEE80211_STYPE_DEAUTH:21312131+ ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);21322132+ break;21332133+ case IEEE80211_STYPE_DISASSOC:21342134+ ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);21352135+ break;16362136 }1637213716382138 kfree_skb(skb);16392139}1640214016411641-16421642-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)16431643-{16441644- struct ieee80211_local *local = sdata->local;16451645- int active = 0;16461646- struct sta_info *sta;16471647-16481648- rcu_read_lock();16491649-16501650- list_for_each_entry_rcu(sta, &local->sta_list, list) {16511651- if (sta->sdata == sdata &&16521652- time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,16531653- jiffies)) {16541654- active++;16551655- break;16561656- }16571657- }16581658-16591659- rcu_read_unlock();16601660-16611661- return active;16621662-}16631663-16641664-16651665-static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,16661666- struct ieee80211_if_sta *ifsta)16671667-{16681668- mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);16691669-16701670- ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);16711671- if (ieee80211_sta_active_ibss(sdata))16721672- return;16731673-16741674- if ((sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) &&16751675- (!(sdata->u.sta.flags & IEEE80211_STA_AUTO_CHANNEL_SEL)))16761676- return;16771677-16781678- printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "16791679- "IBSS networks with same SSID (merge)\n", sdata->dev->name);16801680-16811681- /* XXX maybe racy? */16821682- if (sdata->local->scan_req)16831683- return;16841684-16851685- memcpy(sdata->local->int_scan_req.ssids[0].ssid,16861686- ifsta->ssid, IEEE80211_MAX_SSID_LEN);16871687- sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;16881688- ieee80211_request_scan(sdata, &sdata->local->int_scan_req);16891689-}16901690-16911691-16922141static void ieee80211_sta_timer(unsigned long data)16932142{16942143 struct ieee80211_sub_if_data *sdata =16952144 (struct ieee80211_sub_if_data *) data;16961696- struct ieee80211_if_sta *ifsta = &sdata->u.sta;21452145+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;16972146 struct ieee80211_local *local = sdata->local;1698214716991699- set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);17001700- queue_work(local->hw.workqueue, &ifsta->work);21482148+ set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);21492149+ queue_work(local->hw.workqueue, &ifmgd->work);17012150}1702215117031703-static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,17041704- struct ieee80211_if_sta *ifsta)21522152+static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)17052153{21542154+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;17062155 struct ieee80211_local *local = sdata->local;1707215617082157 if (local->ops->reset_tsf) {···16312238 local->ops->reset_tsf(local_to_hw(local));16322239 }1633224016341634- ifsta->wmm_last_param_set = -1; /* allow any WMM update */22412241+ ifmgd->wmm_last_param_set = -1; /* allow any WMM update */163522421636224316371637- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)16381638- ifsta->auth_alg = WLAN_AUTH_OPEN;16391639- else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)16401640- ifsta->auth_alg = WLAN_AUTH_SHARED_KEY;16411641- else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)16421642- ifsta->auth_alg = WLAN_AUTH_LEAP;22442244+ if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)22452245+ ifmgd->auth_alg = WLAN_AUTH_OPEN;22462246+ else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)22472247+ ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY;22482248+ else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)22492249+ ifmgd->auth_alg = WLAN_AUTH_LEAP;16432250 else16441644- ifsta->auth_alg = WLAN_AUTH_OPEN;16451645- ifsta->auth_transaction = -1;16461646- ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;16471647- ifsta->assoc_scan_tries = 0;16481648- ifsta->direct_probe_tries = 0;16491649- ifsta->auth_tries = 0;16501650- ifsta->assoc_tries = 0;22512251+ ifmgd->auth_alg = WLAN_AUTH_OPEN;22522252+ ifmgd->auth_transaction = -1;22532253+ ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;22542254+ ifmgd->assoc_scan_tries = 0;22552255+ ifmgd->direct_probe_tries = 0;22562256+ ifmgd->auth_tries = 0;22572257+ ifmgd->assoc_tries = 0;16512258 netif_tx_stop_all_queues(sdata->dev);16522259 netif_carrier_off(sdata->dev);16532260}1654226116551655-static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,16561656- struct ieee80211_if_sta *ifsta)22622262+static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)16572263{16581658- struct ieee80211_local *local = sdata->local;16591659- struct ieee80211_supported_band *sband;16601660- u8 *pos;16611661- u8 bssid[ETH_ALEN];16621662- u8 supp_rates[IEEE80211_MAX_SUPP_RATES];16631663- u16 capability;16641664- int i;16651665-16661666- if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) {16671667- memcpy(bssid, ifsta->bssid, ETH_ALEN);16681668- } else {16691669- /* Generate random, not broadcast, locally administered BSSID. Mix in16701670- * own MAC address to make sure that devices that do not have proper16711671- * random number generator get different BSSID. */16721672- get_random_bytes(bssid, ETH_ALEN);16731673- for (i = 0; i < ETH_ALEN; i++)16741674- bssid[i] ^= sdata->dev->dev_addr[i];16751675- bssid[0] &= ~0x01;16761676- bssid[0] |= 0x02;16771677- }16781678-16791679- printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",16801680- sdata->dev->name, bssid);16811681-16821682- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];16831683-16841684- if (local->hw.conf.beacon_int == 0)16851685- local->hw.conf.beacon_int = 100;16861686-16871687- capability = WLAN_CAPABILITY_IBSS;16881688-16891689- if (sdata->default_key)16901690- capability |= WLAN_CAPABILITY_PRIVACY;16911691- else16921692- sdata->drop_unencrypted = 0;16931693-16941694- pos = supp_rates;16951695- for (i = 0; i < sband->n_bitrates; i++) {16961696- int rate = sband->bitrates[i].bitrate;16971697- *pos++ = (u8) (rate / 5);16981698- }16991699-17001700- return __ieee80211_sta_join_ibss(sdata, ifsta,17011701- bssid, local->hw.conf.beacon_int,17021702- local->hw.conf.channel->center_freq,17031703- sband->n_bitrates, supp_rates,17041704- capability);17051705-}17061706-17071707-17081708-static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,17091709- struct ieee80211_if_sta *ifsta)17101710-{22642264+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;17112265 struct ieee80211_local *local = sdata->local;17122266 struct ieee80211_bss *bss;17131713- int active_ibss;17141714-17151715- if (ifsta->ssid_len == 0)17161716- return -EINVAL;17171717-17181718- active_ibss = ieee80211_sta_active_ibss(sdata);17191719-#ifdef CONFIG_MAC80211_IBSS_DEBUG17201720- printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",17211721- sdata->dev->name, active_ibss);17221722-#endif /* CONFIG_MAC80211_IBSS_DEBUG */17231723-17241724- if (active_ibss)17251725- return 0;17261726-17271727- if (ifsta->flags & IEEE80211_STA_BSSID_SET)17281728- bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0,17291729- ifsta->ssid, ifsta->ssid_len);17301730- else17311731- bss = (void *)cfg80211_get_ibss(local->hw.wiphy,17321732- NULL,17331733- ifsta->ssid, ifsta->ssid_len);17341734-17351735-#ifdef CONFIG_MAC80211_IBSS_DEBUG17361736- if (bss)17371737- printk(KERN_DEBUG " sta_find_ibss: selected %pM current "17381738- "%pM\n", bss->cbss.bssid, ifsta->bssid);17391739-#endif /* CONFIG_MAC80211_IBSS_DEBUG */17401740-17411741- if (bss &&17421742- (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) ||17431743- memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) {17441744- int ret;17451745-17461746- printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"17471747- " based on configured SSID\n",17481748- sdata->dev->name, bss->cbss.bssid);17491749-17501750- ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);17511751- ieee80211_rx_bss_put(local, bss);17521752- return ret;17531753- } else if (bss)17541754- ieee80211_rx_bss_put(local, bss);17551755-17561756-#ifdef CONFIG_MAC80211_IBSS_DEBUG17571757- printk(KERN_DEBUG " did not try to join ibss\n");17581758-#endif /* CONFIG_MAC80211_IBSS_DEBUG */17591759-17601760- /* Selected IBSS not found in current scan results - try to scan */17611761- if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED &&17621762- !ieee80211_sta_active_ibss(sdata)) {17631763- mod_timer(&ifsta->timer, jiffies +17641764- IEEE80211_IBSS_MERGE_INTERVAL);17651765- } else if (time_after(jiffies, local->last_scan_completed +17661766- IEEE80211_SCAN_INTERVAL)) {17671767- printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "17681768- "join\n", sdata->dev->name);17691769-17701770- /* XXX maybe racy? */17711771- if (local->scan_req)17721772- return -EBUSY;17731773-17741774- memcpy(local->int_scan_req.ssids[0].ssid,17751775- ifsta->ssid, IEEE80211_MAX_SSID_LEN);17761776- local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;17771777- return ieee80211_request_scan(sdata, &local->int_scan_req);17781778- } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {17791779- int interval = IEEE80211_SCAN_INTERVAL;17801780-17811781- if (time_after(jiffies, ifsta->ibss_join_req +17821782- IEEE80211_IBSS_JOIN_TIMEOUT)) {17831783- if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&17841784- (!(local->oper_channel->flags &17851785- IEEE80211_CHAN_NO_IBSS)))17861786- return ieee80211_sta_create_ibss(sdata, ifsta);17871787- if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {17881788- printk(KERN_DEBUG "%s: IBSS not allowed on"17891789- " %d MHz\n", sdata->dev->name,17901790- local->hw.conf.channel->center_freq);17911791- }17921792-17931793- /* No IBSS found - decrease scan interval and continue17941794- * scanning. */17951795- interval = IEEE80211_SCAN_INTERVAL_SLOW;17961796- }17971797-17981798- ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;17991799- mod_timer(&ifsta->timer, jiffies + interval);18001800- return 0;18011801- }18021802-18031803- return 0;18041804-}18051805-18061806-18071807-static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,18081808- struct ieee80211_if_sta *ifsta)18091809-{18101810- struct ieee80211_local *local = sdata->local;18111811- struct ieee80211_bss *bss;18121812- u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid;18131813- u8 ssid_len = ifsta->ssid_len;22672267+ u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid;22682268+ u8 ssid_len = ifmgd->ssid_len;18142269 u16 capa_mask = WLAN_CAPABILITY_ESS;18152270 u16 capa_val = WLAN_CAPABILITY_ESS;18162271 struct ieee80211_channel *chan = local->oper_channel;1817227218181818- if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |22732273+ if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL |18192274 IEEE80211_STA_AUTO_BSSID_SEL |18202275 IEEE80211_STA_AUTO_CHANNEL_SEL)) {18212276 capa_mask |= WLAN_CAPABILITY_PRIVACY;···16712430 capa_val |= WLAN_CAPABILITY_PRIVACY;16722431 }1673243216741674- if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)24332433+ if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)16752434 chan = NULL;1676243516771677- if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)24362436+ if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL)16782437 bssid = NULL;1679243816801680- if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) {24392439+ if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) {16812440 ssid = NULL;16822441 ssid_len = 0;16832442 }···1688244716892448 if (bss) {16902449 ieee80211_set_freq(sdata, bss->cbss.channel->center_freq);16911691- if (!(ifsta->flags & IEEE80211_STA_SSID_SET))24502450+ if (!(ifmgd->flags & IEEE80211_STA_SSID_SET))16922451 ieee80211_sta_set_ssid(sdata, bss->ssid,16932452 bss->ssid_len);16942453 ieee80211_sta_set_bssid(sdata, bss->cbss.bssid);16952454 ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,16962455 bss->supp_rates);16971697- if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)16981698- sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;24562456+ if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED)24572457+ sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;16992458 else17001700- sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED;24592459+ sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;1701246017022461 /* Send out direct probe if no probe resp was received or17032462 * the one we have is outdated···17052464 if (!bss->last_probe_resp ||17062465 time_after(jiffies, bss->last_probe_resp17072466 + IEEE80211_SCAN_RESULT_EXPIRE))17081708- ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;24672467+ ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;17092468 else17101710- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;24692469+ ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;1711247017122471 ieee80211_rx_bss_put(local, bss);17131713- ieee80211_sta_reset_auth(sdata, ifsta);24722472+ ieee80211_sta_reset_auth(sdata);17142473 return 0;17152474 } else {17161716- if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {17171717- ifsta->assoc_scan_tries++;24752475+ if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {24762476+ ifmgd->assoc_scan_tries++;17182477 /* XXX maybe racy? */17192478 if (local->scan_req)17202479 return -1;17212480 memcpy(local->int_scan_req.ssids[0].ssid,17221722- ifsta->ssid, IEEE80211_MAX_SSID_LEN);17231723- if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)24812481+ ifmgd->ssid, IEEE80211_MAX_SSID_LEN);24822482+ if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)17242483 local->int_scan_req.ssids[0].ssid_len = 0;17252484 else17261726- local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;24852485+ local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len;17272486 ieee80211_start_scan(sdata, &local->int_scan_req);17281728- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;17291729- set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);24872487+ ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;24882488+ set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);17302489 } else {17311731- ifsta->assoc_scan_tries = 0;17321732- ifsta->state = IEEE80211_STA_MLME_DISABLED;24902490+ ifmgd->assoc_scan_tries = 0;24912491+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;17332492 }17342493 }17352494 return -1;···17392498static void ieee80211_sta_work(struct work_struct *work)17402499{17412500 struct ieee80211_sub_if_data *sdata =17421742- container_of(work, struct ieee80211_sub_if_data, u.sta.work);25012501+ container_of(work, struct ieee80211_sub_if_data, u.mgd.work);17432502 struct ieee80211_local *local = sdata->local;17441744- struct ieee80211_if_sta *ifsta;25032503+ struct ieee80211_if_managed *ifmgd;17452504 struct sk_buff *skb;1746250517472506 if (!netif_running(sdata->dev))···17502509 if (local->sw_scanning || local->hw_scanning)17512510 return;1752251117531753- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION &&17541754- sdata->vif.type != NL80211_IFTYPE_ADHOC))25122512+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))17552513 return;17561756- ifsta = &sdata->u.sta;25142514+ ifmgd = &sdata->u.mgd;1757251517581758- while ((skb = skb_dequeue(&ifsta->skb_queue)))25162516+ while ((skb = skb_dequeue(&ifmgd->skb_queue)))17592517 ieee80211_sta_rx_queued_mgmt(sdata, skb);1760251817611761- if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&17621762- ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&17631763- ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&17641764- test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {25192519+ if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE &&25202520+ ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&25212521+ ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&25222522+ test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {17652523 ieee80211_start_scan(sdata, local->scan_req);17662524 return;17672525 }1768252617691769- if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {17701770- if (ieee80211_sta_config_auth(sdata, ifsta))25272527+ if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) {25282528+ if (ieee80211_sta_config_auth(sdata))17712529 return;17721772- clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);17731773- } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))25302530+ clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);25312531+ } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))17742532 return;1775253317761776- switch (ifsta->state) {25342534+ switch (ifmgd->state) {17772535 case IEEE80211_STA_MLME_DISABLED:17782536 break;17792537 case IEEE80211_STA_MLME_DIRECT_PROBE:17801780- ieee80211_direct_probe(sdata, ifsta);25382538+ ieee80211_direct_probe(sdata);17812539 break;17822540 case IEEE80211_STA_MLME_AUTHENTICATE:17831783- ieee80211_authenticate(sdata, ifsta);25412541+ ieee80211_authenticate(sdata);17842542 break;17852543 case IEEE80211_STA_MLME_ASSOCIATE:17861786- ieee80211_associate(sdata, ifsta);25442544+ ieee80211_associate(sdata);17872545 break;17882546 case IEEE80211_STA_MLME_ASSOCIATED:17891789- ieee80211_associated(sdata, ifsta);17901790- break;17911791- case IEEE80211_STA_MLME_IBSS_SEARCH:17921792- ieee80211_sta_find_ibss(sdata, ifsta);17931793- break;17941794- case IEEE80211_STA_MLME_IBSS_JOINED:17951795- ieee80211_sta_merge_ibss(sdata, ifsta);25472547+ ieee80211_associated(sdata);17962548 break;17972549 default:17982550 WARN_ON(1);17992551 break;18002552 }1801255318021802- if (ieee80211_privacy_mismatch(sdata, ifsta)) {25542554+ if (ieee80211_privacy_mismatch(sdata)) {18032555 printk(KERN_DEBUG "%s: privacy configuration mismatch and "18042556 "mixed-cell disabled - disassociate\n", sdata->dev->name);1805255718061806- ieee80211_set_disassoc(sdata, ifsta, false, true,25582558+ ieee80211_set_disassoc(sdata, false, true,18072559 WLAN_REASON_UNSPECIFIED);18082560 }18092561}···18052571{18062572 if (sdata->vif.type == NL80211_IFTYPE_STATION)18072573 queue_work(sdata->local->hw.workqueue,18081808- &sdata->u.sta.work);25742574+ &sdata->u.mgd.work);18092575}1810257618112577/* interface setup */18122578void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)18132579{18141814- struct ieee80211_if_sta *ifsta;25802580+ struct ieee80211_if_managed *ifmgd;1815258118161816- ifsta = &sdata->u.sta;18171817- INIT_WORK(&ifsta->work, ieee80211_sta_work);18181818- INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work);18191819- setup_timer(&ifsta->timer, ieee80211_sta_timer,25822582+ ifmgd = &sdata->u.mgd;25832583+ INIT_WORK(&ifmgd->work, ieee80211_sta_work);25842584+ INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);25852585+ setup_timer(&ifmgd->timer, ieee80211_sta_timer,18202586 (unsigned long) sdata);18211821- setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer,25872587+ setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,18222588 (unsigned long) sdata);18231823- skb_queue_head_init(&ifsta->skb_queue);25892589+ skb_queue_head_init(&ifmgd->skb_queue);1824259018251825- ifsta->capab = WLAN_CAPABILITY_ESS;18261826- ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |25912591+ ifmgd->capab = WLAN_CAPABILITY_ESS;25922592+ ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN |18272593 IEEE80211_AUTH_ALG_SHARED_KEY;18281828- ifsta->flags |= IEEE80211_STA_CREATE_IBSS |25942594+ ifmgd->flags |= IEEE80211_STA_CREATE_IBSS |18292595 IEEE80211_STA_AUTO_BSSID_SEL |18302596 IEEE80211_STA_AUTO_CHANNEL_SEL;18312597 if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)18321832- ifsta->flags |= IEEE80211_STA_WMM_ENABLED;18331833-}18341834-18351835-/*18361836- * Add a new IBSS station, will also be called by the RX code when,18371837- * in IBSS mode, receiving a frame from a yet-unknown station, hence18381838- * must be callable in atomic context.18391839- */18401840-struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,18411841- u8 *bssid,u8 *addr, u32 supp_rates)18421842-{18431843- struct ieee80211_local *local = sdata->local;18441844- struct sta_info *sta;18451845- int band = local->hw.conf.channel->band;18461846-18471847- /* TODO: Could consider removing the least recently used entry and18481848- * allow new one to be added. */18491849- if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {18501850- if (net_ratelimit()) {18511851- printk(KERN_DEBUG "%s: No room for a new IBSS STA "18521852- "entry %pM\n", sdata->dev->name, addr);18531853- }18541854- return NULL;18551855- }18561856-18571857- if (compare_ether_addr(bssid, sdata->u.sta.bssid))18581858- return NULL;18591859-18601860-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG18611861- printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",18621862- wiphy_name(local->hw.wiphy), addr, sdata->dev->name);18631863-#endif18641864-18651865- sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);18661866- if (!sta)18671867- return NULL;18681868-18691869- set_sta_flags(sta, WLAN_STA_AUTHORIZED);18701870-18711871- /* make sure mandatory rates are always added */18721872- sta->sta.supp_rates[band] = supp_rates |18731873- ieee80211_mandatory_rates(local, band);18741874-18751875- rate_control_rate_init(sta);18761876-18771877- if (sta_info_insert(sta))18781878- return NULL;18791879-18801880- return sta;25982598+ ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;18812599}1882260018832601/* configuration hooks */18841884-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,18851885- struct ieee80211_if_sta *ifsta)26022602+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)18862603{26042604+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;18872605 struct ieee80211_local *local = sdata->local;1888260618891889- if (sdata->vif.type != NL80211_IFTYPE_STATION)26072607+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))18902608 return;1891260918921892- if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |26102610+ if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET |18932611 IEEE80211_STA_AUTO_BSSID_SEL)) &&18941894- (ifsta->flags & (IEEE80211_STA_SSID_SET |26122612+ (ifmgd->flags & (IEEE80211_STA_SSID_SET |18952613 IEEE80211_STA_AUTO_SSID_SEL))) {1896261418971897- if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED)18981898- ieee80211_set_disassoc(sdata, ifsta, true, true,26152615+ if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)26162616+ ieee80211_set_disassoc(sdata, true, true,18992617 WLAN_REASON_DEAUTH_LEAVING);1900261819011901- set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);19021902- queue_work(local->hw.workqueue, &ifsta->work);26192619+ set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);26202620+ queue_work(local->hw.workqueue, &ifmgd->work);19032621 }19042622}1905262319061906-int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)26242624+int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata)19072625{19081908- struct ieee80211_if_sta *ifsta;26262626+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;1909262719101910- if (len > IEEE80211_MAX_SSID_LEN)19111911- return -EINVAL;26282628+ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;1912262919131913- ifsta = &sdata->u.sta;19141914-19151915- if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {19161916- memset(ifsta->ssid, 0, sizeof(ifsta->ssid));19171917- memcpy(ifsta->ssid, ssid, len);19181918- ifsta->ssid_len = len;19191919- }19201920-19211921- ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;19221922-19231923- if (len)19241924- ifsta->flags |= IEEE80211_STA_SSID_SET;26302630+ if (ifmgd->ssid_len)26312631+ ifmgd->flags |= IEEE80211_STA_SSID_SET;19252632 else19261926- ifsta->flags &= ~IEEE80211_STA_SSID_SET;19271927-19281928- if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {19291929- ifsta->ibss_join_req = jiffies;19301930- ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;19311931- return ieee80211_sta_find_ibss(sdata, ifsta);19321932- }26332633+ ifmgd->flags &= ~IEEE80211_STA_SSID_SET;1933263419342635 return 0;19352636}1936263726382638+int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)26392639+{26402640+ struct ieee80211_if_managed *ifmgd;26412641+26422642+ if (len > IEEE80211_MAX_SSID_LEN)26432643+ return -EINVAL;26442644+26452645+ ifmgd = &sdata->u.mgd;26462646+26472647+ if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) {26482648+ memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid));26492649+ memcpy(ifmgd->ssid, ssid, len);26502650+ ifmgd->ssid_len = len;26512651+ }26522652+26532653+ return ieee80211_sta_commit(sdata);26542654+}26552655+19372656int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)19382657{19391939- struct ieee80211_if_sta *ifsta = &sdata->u.sta;19401940- memcpy(ssid, ifsta->ssid, ifsta->ssid_len);19411941- *len = ifsta->ssid_len;26582658+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;26592659+ memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len);26602660+ *len = ifmgd->ssid_len;19422661 return 0;19432662}1944266319452664int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)19462665{19471947- struct ieee80211_if_sta *ifsta;19481948-19491949- ifsta = &sdata->u.sta;26662666+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;1950266719512668 if (is_valid_ether_addr(bssid)) {19521952- memcpy(ifsta->bssid, bssid, ETH_ALEN);19531953- ifsta->flags |= IEEE80211_STA_BSSID_SET;26692669+ memcpy(ifmgd->bssid, bssid, ETH_ALEN);26702670+ ifmgd->flags |= IEEE80211_STA_BSSID_SET;19542671 } else {19551955- memset(ifsta->bssid, 0, ETH_ALEN);19561956- ifsta->flags &= ~IEEE80211_STA_BSSID_SET;26722672+ memset(ifmgd->bssid, 0, ETH_ALEN);26732673+ ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;19572674 }1958267519592676 if (netif_running(sdata->dev)) {···19142729 }19152730 }1916273119171917- return ieee80211_sta_set_ssid(sdata, ifsta->ssid, ifsta->ssid_len);27322732+ return ieee80211_sta_commit(sdata);19182733}1919273419202735int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len)19212736{19221922- struct ieee80211_if_sta *ifsta = &sdata->u.sta;27372737+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;1923273819241924- kfree(ifsta->extra_ie);27392739+ kfree(ifmgd->extra_ie);19252740 if (len == 0) {19261926- ifsta->extra_ie = NULL;19271927- ifsta->extra_ie_len = 0;27412741+ ifmgd->extra_ie = NULL;27422742+ ifmgd->extra_ie_len = 0;19282743 return 0;19292744 }19301930- ifsta->extra_ie = kmalloc(len, GFP_KERNEL);19311931- if (!ifsta->extra_ie) {19321932- ifsta->extra_ie_len = 0;27452745+ ifmgd->extra_ie = kmalloc(len, GFP_KERNEL);27462746+ if (!ifmgd->extra_ie) {27472747+ ifmgd->extra_ie_len = 0;19332748 return -ENOMEM;19342749 }19351935- memcpy(ifsta->extra_ie, ie, len);19361936- ifsta->extra_ie_len = len;27502750+ memcpy(ifmgd->extra_ie, ie, len);27512751+ ifmgd->extra_ie_len = len;19372752 return 0;19382753}1939275419402755int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)19412756{19421942- struct ieee80211_if_sta *ifsta = &sdata->u.sta;19431943-19442757 printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",19452758 sdata->dev->name, reason);1946275919471947- if (sdata->vif.type != NL80211_IFTYPE_STATION &&19481948- sdata->vif.type != NL80211_IFTYPE_ADHOC)27602760+ if (sdata->vif.type != NL80211_IFTYPE_STATION)19492761 return -EINVAL;1950276219511951- ieee80211_set_disassoc(sdata, ifsta, true, true, reason);27632763+ ieee80211_set_disassoc(sdata, true, true, reason);19522764 return 0;19532765}1954276619552767int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)19562768{19571957- struct ieee80211_if_sta *ifsta = &sdata->u.sta;27692769+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;1958277019592771 printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",19602772 sdata->dev->name, reason);···19592777 if (sdata->vif.type != NL80211_IFTYPE_STATION)19602778 return -EINVAL;1961277919621962- if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))19631963- return -1;27802780+ if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))27812781+ return -ENOLINK;1964278219651965- ieee80211_set_disassoc(sdata, ifsta, false, true, reason);27832783+ ieee80211_set_disassoc(sdata, false, true, reason);19662784 return 0;19672785}19682786···19702788void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)19712789{19722790 struct ieee80211_sub_if_data *sdata = local->scan_sdata;19731973- struct ieee80211_if_sta *ifsta;19741974-19751975- if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {19761976- ifsta = &sdata->u.sta;19771977- if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||19781978- !ieee80211_sta_active_ibss(sdata))19791979- ieee80211_sta_find_ibss(sdata, ifsta);19801980- }1981279119822792 /* Restart STA timers */19832793 rcu_read_lock();···20152841 struct ieee80211_local *local = (void *) data;2016284220172843 queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);28442844+}28452845+28462846+void ieee80211_send_nullfunc(struct ieee80211_local *local,28472847+ struct ieee80211_sub_if_data *sdata,28482848+ int powersave)28492849+{28502850+ struct sk_buff *skb;28512851+ struct ieee80211_hdr *nullfunc;28522852+ __le16 fc;28532853+28542854+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))28552855+ return;28562856+28572857+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);28582858+ if (!skb) {28592859+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "28602860+ "frame\n", sdata->dev->name);28612861+ return;28622862+ }28632863+ skb_reserve(skb, local->hw.extra_tx_headroom);28642864+28652865+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);28662866+ memset(nullfunc, 0, 24);28672867+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |28682868+ IEEE80211_FCTL_TODS);28692869+ if (powersave)28702870+ fc |= cpu_to_le16(IEEE80211_FCTL_PM);28712871+ nullfunc->frame_control = fc;28722872+ memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);28732873+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);28742874+ memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);28752875+28762876+ ieee80211_tx_skb(sdata, skb, 0);20182877}
···202202 /* Make sure timer won't free the tid_rx struct, see below */203203 if (tid_rx)204204 tid_rx->shutdown = true;205205+206206+ /*207207+ * The stop callback cannot find this station any more, but208208+ * it didn't complete its work -- start the queue if necessary209209+ */210210+ if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK &&211211+ sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK &&212212+ local->hw.ampdu_queues)213213+ ieee80211_wake_queue_by_reason(&local->hw,214214+ local->hw.queues + sta->tid_to_tx_q[i],215215+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);216216+205217 spin_unlock_bh(&sta->lock);206218207219 /*···287275 * enable session_timer's data differentiation. refer to288276 * sta_rx_agg_session_timer_expired for useage */289277 sta->timer_to_tid[i] = i;290290- /* tid to tx queue: initialize according to HW (0 is valid) */291291- sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);278278+ sta->tid_to_tx_q[i] = -1;292279 /* rx */293280 sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;294281 sta->ampdu_mlme.tid_rx[i] = NULL;
+3-2
net/mac80211/sta_info.h
···9090 * @buf_size: buffer size for incoming A-MPDUs9191 * @timeout: reset timer value (in TUs).9292 * @dialog_token: dialog token for aggregation session9393+ * @shutdown: this session is being shut down due to STA removal9394 */9495struct tid_ampdu_rx {9596 struct sk_buff **reorder_buf;···201200 * @tid_seq: per-TID sequence numbers for sending to this STA202201 * @ampdu_mlme: A-MPDU state machine state203202 * @timer_to_tid: identity mapping to ID timers204204- * @tid_to_tx_q: map tid to tx queue203203+ * @tid_to_tx_q: map tid to tx queue (invalid == negative values)205204 * @llid: Local link ID206205 * @plid: Peer link ID207206 * @reason: Cancel reason on PLINK_HOLDING state···276275 */277276 struct sta_ampdu_mlme ampdu_mlme;278277 u8 timer_to_tid[STA_TID_NUM];279279- u8 tid_to_tx_q[STA_TID_NUM];278278+ s8 tid_to_tx_q[STA_TID_NUM];280279281280#ifdef CONFIG_MAC80211_MESH282281 /*
+18-11
net/mac80211/tx.c
···876876 return TX_CONTINUE;877877}878878879879-880879/* actual transmit path */881880882881/*···10151016 tx->sta = sta_info_get(local, hdr->addr1);1016101710171018 if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) {10191019+ unsigned long flags;10181020 qc = ieee80211_get_qos_ctl(hdr);10191021 tid = *qc & IEEE80211_QOS_CTL_TID_MASK;1020102210231023+ spin_lock_irqsave(&tx->sta->lock, flags);10211024 state = &tx->sta->ampdu_mlme.tid_state_tx[tid];10221022- if (*state == HT_AGG_STATE_OPERATIONAL)10251025+ if (*state == HT_AGG_STATE_OPERATIONAL) {10231026 info->flags |= IEEE80211_TX_CTL_AMPDU;10271027+ if (local->hw.ampdu_queues)10281028+ skb_set_queue_mapping(10291029+ skb, tx->local->hw.queues +10301030+ tx->sta->tid_to_tx_q[tid]);10311031+ }10321032+ spin_unlock_irqrestore(&tx->sta->lock, flags);10241033 }1025103410261035 if (is_multicast_ether_addr(hdr->addr1)) {···10921085 int ret, i;1093108610941087 if (skb) {10951095- if (netif_subqueue_stopped(local->mdev, skb))10881088+ if (ieee80211_queue_stopped(&local->hw,10891089+ skb_get_queue_mapping(skb)))10961090 return IEEE80211_TX_PENDING;1097109110981092 ret = local->ops->tx(local_to_hw(local), skb);···11091101 info = IEEE80211_SKB_CB(tx->extra_frag[i]);11101102 info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |11111103 IEEE80211_TX_CTL_FIRST_FRAGMENT);11121112- if (netif_subqueue_stopped(local->mdev,11131113- tx->extra_frag[i]))11041104+ if (ieee80211_queue_stopped(&local->hw,11051105+ skb_get_queue_mapping(tx->extra_frag[i])))11141106 return IEEE80211_TX_FRAG_AGAIN;1115110711161108 ret = local->ops->tx(local_to_hw(local),···16331625 case NL80211_IFTYPE_STATION:16341626 fc |= cpu_to_le16(IEEE80211_FCTL_TODS);16351627 /* BSSID SA DA */16361636- memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);16281628+ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);16371629 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);16381630 memcpy(hdr.addr3, skb->data, ETH_ALEN);16391631 hdrlen = 24;···16421634 /* DA SA BSSID */16431635 memcpy(hdr.addr1, skb->data, ETH_ALEN);16441636 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);16451645- memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);16371637+ memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);16461638 hdrlen = 24;16471639 break;16481640 default:···19281920 struct ieee80211_tx_info *info;19291921 struct ieee80211_sub_if_data *sdata = NULL;19301922 struct ieee80211_if_ap *ap = NULL;19311931- struct ieee80211_if_sta *ifsta = NULL;19321923 struct beacon_data *beacon;19331924 struct ieee80211_supported_band *sband;19341925 enum ieee80211_band band = local->hw.conf.channel->band;···19791972 } else19801973 goto out;19811974 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {19751975+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;19821976 struct ieee80211_hdr *hdr;19831983- ifsta = &sdata->u.sta;1984197719851985- if (!ifsta->probe_resp)19781978+ if (!ifibss->probe_resp)19861979 goto out;1987198019881988- skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);19811981+ skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC);19891982 if (!skb)19901983 goto out;19911984
+242-14
net/mac80211/util.c
···344344{345345 struct ieee80211_local *local = hw_to_local(hw);346346347347- /* we don't need to track ampdu queues */348348- if (queue < ieee80211_num_regular_queues(hw)) {349349- __clear_bit(reason, &local->queue_stop_reasons[queue]);350350-351351- if (local->queue_stop_reasons[queue] != 0)352352- /* someone still has this queue stopped */347347+ if (queue >= hw->queues) {348348+ if (local->ampdu_ac_queue[queue - hw->queues] < 0)353349 return;350350+351351+ /*352352+ * for virtual aggregation queues, we need to refcount the353353+ * internal mac80211 disable (multiple times!), keep track of354354+ * driver disable _and_ make sure the regular queue is355355+ * actually enabled.356356+ */357357+ if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)358358+ local->amdpu_ac_stop_refcnt[queue - hw->queues]--;359359+ else360360+ __clear_bit(reason, &local->queue_stop_reasons[queue]);361361+362362+ if (local->queue_stop_reasons[queue] ||363363+ local->amdpu_ac_stop_refcnt[queue - hw->queues])364364+ return;365365+366366+ /* now go on to treat the corresponding regular queue */367367+ queue = local->ampdu_ac_queue[queue - hw->queues];368368+ reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;354369 }370370+371371+ __clear_bit(reason, &local->queue_stop_reasons[queue]);372372+373373+ if (local->queue_stop_reasons[queue] != 0)374374+ /* someone still has this queue stopped */375375+ return;355376356377 if (test_bit(queue, local->queues_pending)) {357378 set_bit(queue, local->queues_pending_run);···382361 }383362}384363385385-static void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,386386- enum queue_stop_reason reason)364364+void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,365365+ enum queue_stop_reason reason)387366{388367 struct ieee80211_local *local = hw_to_local(hw);389368 unsigned long flags;···405384{406385 struct ieee80211_local *local = hw_to_local(hw);407386408408- /* we don't need to track ampdu queues */409409- if (queue < ieee80211_num_regular_queues(hw))410410- __set_bit(reason, &local->queue_stop_reasons[queue]);387387+ if (queue >= hw->queues) {388388+ if (local->ampdu_ac_queue[queue - hw->queues] < 0)389389+ return;390390+391391+ /*392392+ * for virtual aggregation queues, we need to refcount the393393+ * internal mac80211 disable (multiple times!), keep track of394394+ * driver disable _and_ make sure the regular queue is395395+ * actually enabled.396396+ */397397+ if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)398398+ local->amdpu_ac_stop_refcnt[queue - hw->queues]++;399399+ else400400+ __set_bit(reason, &local->queue_stop_reasons[queue]);401401+402402+ /* now go on to treat the corresponding regular queue */403403+ queue = local->ampdu_ac_queue[queue - hw->queues];404404+ reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;405405+ }406406+407407+ __set_bit(reason, &local->queue_stop_reasons[queue]);411408412409 netif_stop_subqueue(local->mdev, queue);413410}414411415415-static void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,416416- enum queue_stop_reason reason)412412+void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,413413+ enum queue_stop_reason reason)417414{418415 struct ieee80211_local *local = hw_to_local(hw);419416 unsigned long flags;···457418458419 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);459420460460- for (i = 0; i < ieee80211_num_queues(hw); i++)421421+ for (i = 0; i < hw->queues; i++)461422 __ieee80211_stop_queue(hw, i, reason);462423463424 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);···473434int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)474435{475436 struct ieee80211_local *local = hw_to_local(hw);437437+ unsigned long flags;438438+439439+ if (queue >= hw->queues) {440440+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);441441+ queue = local->ampdu_ac_queue[queue - hw->queues];442442+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);443443+ if (queue < 0)444444+ return true;445445+ }446446+476447 return __netif_subqueue_stopped(local->mdev, queue);477448}478449EXPORT_SYMBOL(ieee80211_queue_stopped);···750701 local->ops->conf_tx(local_to_hw(local), i, &qparam);751702}752703704704+void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,705705+ const size_t supp_rates_len,706706+ const u8 *supp_rates)707707+{708708+ struct ieee80211_local *local = sdata->local;709709+ int i, have_higher_than_11mbit = 0;710710+711711+ /* cf. IEEE 802.11 9.2.12 */712712+ for (i = 0; i < supp_rates_len; i++)713713+ if ((supp_rates[i] & 0x7f) * 5 > 110)714714+ have_higher_than_11mbit = 1;715715+716716+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&717717+ have_higher_than_11mbit)718718+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;719719+ else720720+ sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;721721+722722+ ieee80211_set_wmm_default(sdata);723723+}724724+753725void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,754726 int encrypt)755727{···836766 if (bitrates[i].flags & mandatory_flag)837767 mandatory_rates |= BIT(i);838768 return mandatory_rates;769769+}770770+771771+void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,772772+ u16 transaction, u16 auth_alg,773773+ u8 *extra, size_t extra_len,774774+ const u8 *bssid, int encrypt)775775+{776776+ struct ieee80211_local *local = sdata->local;777777+ struct sk_buff *skb;778778+ struct ieee80211_mgmt *mgmt;779779+ const u8 *ie_auth = NULL;780780+ int ie_auth_len = 0;781781+782782+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {783783+ ie_auth_len = sdata->u.mgd.ie_auth_len;784784+ ie_auth = sdata->u.mgd.ie_auth;785785+ }786786+787787+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +788788+ sizeof(*mgmt) + 6 + extra_len + ie_auth_len);789789+ if (!skb) {790790+ printk(KERN_DEBUG "%s: failed to allocate buffer for auth "791791+ "frame\n", sdata->dev->name);792792+ return;793793+ }794794+ skb_reserve(skb, local->hw.extra_tx_headroom);795795+796796+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);797797+ memset(mgmt, 0, 24 + 6);798798+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |799799+ IEEE80211_STYPE_AUTH);800800+ if (encrypt)801801+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);802802+ memcpy(mgmt->da, bssid, ETH_ALEN);803803+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);804804+ memcpy(mgmt->bssid, bssid, ETH_ALEN);805805+ mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);806806+ mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);807807+ mgmt->u.auth.status_code = cpu_to_le16(0);808808+ if (extra)809809+ memcpy(skb_put(skb, extra_len), extra, extra_len);810810+ if (ie_auth)811811+ memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len);812812+813813+ ieee80211_tx_skb(sdata, skb, encrypt);814814+}815815+816816+void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,817817+ u8 *ssid, size_t ssid_len,818818+ u8 *ie, size_t ie_len)819819+{820820+ struct ieee80211_local *local = sdata->local;821821+ struct ieee80211_supported_band *sband;822822+ struct sk_buff *skb;823823+ struct ieee80211_mgmt *mgmt;824824+ u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL;825825+ int i, extra_preq_ie_len = 0;826826+827827+ switch (sdata->vif.type) {828828+ case NL80211_IFTYPE_STATION:829829+ extra_preq_ie_len = sdata->u.mgd.ie_probereq_len;830830+ extra_preq_ie = sdata->u.mgd.ie_probereq;831831+ break;832832+ default:833833+ break;834834+ }835835+836836+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +837837+ ie_len + extra_preq_ie_len);838838+ if (!skb) {839839+ printk(KERN_DEBUG "%s: failed to allocate buffer for probe "840840+ "request\n", sdata->dev->name);841841+ return;842842+ }843843+ skb_reserve(skb, local->hw.extra_tx_headroom);844844+845845+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);846846+ memset(mgmt, 0, 24);847847+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |848848+ IEEE80211_STYPE_PROBE_REQ);849849+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);850850+ if (dst) {851851+ memcpy(mgmt->da, dst, ETH_ALEN);852852+ memcpy(mgmt->bssid, dst, ETH_ALEN);853853+ } else {854854+ memset(mgmt->da, 0xff, ETH_ALEN);855855+ memset(mgmt->bssid, 0xff, ETH_ALEN);856856+ }857857+ pos = skb_put(skb, 2 + ssid_len);858858+ *pos++ = WLAN_EID_SSID;859859+ *pos++ = ssid_len;860860+ memcpy(pos, ssid, ssid_len);861861+862862+ supp_rates = skb_put(skb, 2);863863+ supp_rates[0] = WLAN_EID_SUPP_RATES;864864+ supp_rates[1] = 0;865865+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];866866+867867+ for (i = 0; i < sband->n_bitrates; i++) {868868+ struct ieee80211_rate *rate = &sband->bitrates[i];869869+ if (esupp_rates) {870870+ pos = skb_put(skb, 1);871871+ esupp_rates[1]++;872872+ } else if (supp_rates[1] == 8) {873873+ esupp_rates = skb_put(skb, 3);874874+ esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;875875+ esupp_rates[1] = 1;876876+ pos = &esupp_rates[2];877877+ } else {878878+ pos = skb_put(skb, 1);879879+ supp_rates[1]++;880880+ }881881+ *pos = rate->bitrate / 5;882882+ }883883+884884+ if (ie)885885+ memcpy(skb_put(skb, ie_len), ie, ie_len);886886+ if (extra_preq_ie)887887+ memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie,888888+ extra_preq_ie_len);889889+890890+ ieee80211_tx_skb(sdata, skb, 0);891891+}892892+893893+u32 ieee80211_sta_get_rates(struct ieee80211_local *local,894894+ struct ieee802_11_elems *elems,895895+ enum ieee80211_band band)896896+{897897+ struct ieee80211_supported_band *sband;898898+ struct ieee80211_rate *bitrates;899899+ size_t num_rates;900900+ u32 supp_rates;901901+ int i, j;902902+ sband = local->hw.wiphy->bands[band];903903+904904+ if (!sband) {905905+ WARN_ON(1);906906+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];907907+ }908908+909909+ bitrates = sband->bitrates;910910+ num_rates = sband->n_bitrates;911911+ supp_rates = 0;912912+ for (i = 0; i < elems->supp_rates_len +913913+ elems->ext_supp_rates_len; i++) {914914+ u8 rate = 0;915915+ int own_rate;916916+ if (i < elems->supp_rates_len)917917+ rate = elems->supp_rates[i];918918+ else if (elems->ext_supp_rates)919919+ rate = elems->ext_supp_rates920920+ [i - elems->supp_rates_len];921921+ own_rate = 5 * (rate & 0x7f);922922+ for (j = 0; j < num_rates; j++)923923+ if (bitrates[j].bitrate == own_rate)924924+ supp_rates |= BIT(j);925925+ }926926+ return supp_rates;839927}
+96-166
net/mac80211/wext.c
···132132 if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)133133 return -EOPNOTSUPP;134134135135- if (sdata->vif.type == NL80211_IFTYPE_STATION ||136136- sdata->vif.type == NL80211_IFTYPE_ADHOC) {135135+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {137136 int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);138137 if (ret)139138 return ret;140140- sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;141141- ieee80211_sta_req_auth(sdata, &sdata->u.sta);139139+ sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;140140+ ieee80211_sta_req_auth(sdata);142141 return 0;143142 }144143145144 return -EOPNOTSUPP;146145}147147-148148-static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)149149-{150150- u8 wstats_flags = 0;151151-152152- wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |153153- IEEE80211_HW_SIGNAL_DBM) ?154154- IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;155155- wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?156156- IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;157157- if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)158158- wstats_flags |= IW_QUAL_DBM;159159-160160- return wstats_flags;161161-}162162-163163-static int ieee80211_ioctl_giwrange(struct net_device *dev,164164- struct iw_request_info *info,165165- struct iw_point *data, char *extra)166166-{167167- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);168168- struct iw_range *range = (struct iw_range *) extra;169169- enum ieee80211_band band;170170- int c = 0;171171-172172- data->length = sizeof(struct iw_range);173173- memset(range, 0, sizeof(struct iw_range));174174-175175- range->we_version_compiled = WIRELESS_EXT;176176- range->we_version_source = 21;177177- range->retry_capa = IW_RETRY_LIMIT;178178- range->retry_flags = IW_RETRY_LIMIT;179179- range->min_retry = 0;180180- range->max_retry = 255;181181- range->min_rts = 0;182182- range->max_rts = 2347;183183- range->min_frag = 256;184184- range->max_frag = 2346;185185-186186- range->encoding_size[0] = 5;187187- range->encoding_size[1] = 13;188188- range->num_encoding_sizes = 2;189189- range->max_encoding_tokens = NUM_DEFAULT_KEYS;190190-191191- /* cfg80211 requires this, and enforces 0..100 */192192- if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)193193- range->max_qual.level = 100;194194- else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)195195- range->max_qual.level = -110;196196- else197197- range->max_qual.level = 0;198198-199199- if (local->hw.flags & IEEE80211_HW_NOISE_DBM)200200- range->max_qual.noise = -110;201201- else202202- range->max_qual.noise = 0;203203-204204- range->max_qual.qual = 100;205205- range->max_qual.updated = ieee80211_get_wstats_flags(local);206206-207207- range->avg_qual.qual = 50;208208- /* not always true but better than nothing */209209- range->avg_qual.level = range->max_qual.level / 2;210210- range->avg_qual.noise = range->max_qual.noise / 2;211211- range->avg_qual.updated = ieee80211_get_wstats_flags(local);212212-213213- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |214214- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;215215-216216-217217- for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {218218- int i;219219- struct ieee80211_supported_band *sband;220220-221221- sband = local->hw.wiphy->bands[band];222222-223223- if (!sband)224224- continue;225225-226226- for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {227227- struct ieee80211_channel *chan = &sband->channels[i];228228-229229- if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {230230- range->freq[c].i =231231- ieee80211_frequency_to_channel(232232- chan->center_freq);233233- range->freq[c].m = chan->center_freq;234234- range->freq[c].e = 6;235235- c++;236236- }237237- }238238- }239239- range->num_channels = c;240240- range->num_frequency = c;241241-242242- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);243243- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);244244- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);245245-246246- range->scan_capa |= IW_SCAN_CAPA_ESSID;247247-248248- return 0;249249-}250250-251146252147static int ieee80211_ioctl_siwfreq(struct net_device *dev,253148 struct iw_request_info *info,···150255{151256 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);152257153153- if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||154154- sdata->vif.type == NL80211_IFTYPE_STATION)155155- sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;258258+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)259259+ sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL;260260+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)261261+ sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;156262157263 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */158264 if (freq->e == 0) {159265 if (freq->m < 0) {160160- if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||161161- sdata->vif.type == NL80211_IFTYPE_STATION)162162- sdata->u.sta.flags |=266266+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)267267+ sdata->u.ibss.flags |=268268+ IEEE80211_IBSS_AUTO_CHANNEL_SEL;269269+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)270270+ sdata->u.mgd.flags |=163271 IEEE80211_STA_AUTO_CHANNEL_SEL;164272 return 0;165273 } else···199301{200302 struct ieee80211_sub_if_data *sdata;201303 size_t len = data->length;304304+ int ret;202305203306 /* iwconfig uses nul termination in SSID.. */204307 if (len > 0 && ssid[len - 1] == '\0')205308 len--;206309207310 sdata = IEEE80211_DEV_TO_SUB_IF(dev);208208- if (sdata->vif.type == NL80211_IFTYPE_STATION ||209209- sdata->vif.type == NL80211_IFTYPE_ADHOC) {210210- int ret;311311+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {211312 if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {212313 if (len > IEEE80211_MAX_SSID_LEN)213314 return -EINVAL;214214- memcpy(sdata->u.sta.ssid, ssid, len);215215- sdata->u.sta.ssid_len = len;315315+ memcpy(sdata->u.mgd.ssid, ssid, len);316316+ sdata->u.mgd.ssid_len = len;216317 return 0;217318 }319319+218320 if (data->flags)219219- sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;321321+ sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;220322 else221221- sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;323323+ sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;324324+222325 ret = ieee80211_sta_set_ssid(sdata, ssid, len);223326 if (ret)224327 return ret;225225- ieee80211_sta_req_auth(sdata, &sdata->u.sta);328328+329329+ ieee80211_sta_req_auth(sdata);226330 return 0;227227- }331331+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)332332+ return ieee80211_ibss_set_ssid(sdata, ssid, len);228333229334 return -EOPNOTSUPP;230335}···241340242341 struct ieee80211_sub_if_data *sdata;243342 sdata = IEEE80211_DEV_TO_SUB_IF(dev);244244- if (sdata->vif.type == NL80211_IFTYPE_STATION ||245245- sdata->vif.type == NL80211_IFTYPE_ADHOC) {343343+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {246344 int res = ieee80211_sta_get_ssid(sdata, ssid, &len);345345+ if (res == 0) {346346+ data->length = len;347347+ data->flags = 1;348348+ } else349349+ data->flags = 0;350350+ return res;351351+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {352352+ int res = ieee80211_ibss_get_ssid(sdata, ssid, &len);247353 if (res == 0) {248354 data->length = len;249355 data->flags = 1;···270362 struct ieee80211_sub_if_data *sdata;271363272364 sdata = IEEE80211_DEV_TO_SUB_IF(dev);273273- if (sdata->vif.type == NL80211_IFTYPE_STATION ||274274- sdata->vif.type == NL80211_IFTYPE_ADHOC) {365365+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {275366 int ret;276367 if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {277277- memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,368368+ memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data,278369 ETH_ALEN);279370 return 0;280371 }281372 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))282282- sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |373373+ sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |283374 IEEE80211_STA_AUTO_CHANNEL_SEL;284375 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))285285- sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;376376+ sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;286377 else287287- sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;378378+ sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;288379 ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);289380 if (ret)290381 return ret;291291- ieee80211_sta_req_auth(sdata, &sdata->u.sta);382382+ ieee80211_sta_req_auth(sdata);292383 return 0;384384+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {385385+ if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))386386+ sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |387387+ IEEE80211_IBSS_AUTO_CHANNEL_SEL;388388+ else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))389389+ sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL;390390+ else391391+ sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL;392392+393393+ return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data);293394 } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {294395 /*295396 * If it is necessary to update the WDS peer address···327410 struct ieee80211_sub_if_data *sdata;328411329412 sdata = IEEE80211_DEV_TO_SUB_IF(dev);330330- if (sdata->vif.type == NL80211_IFTYPE_STATION ||331331- sdata->vif.type == NL80211_IFTYPE_ADHOC) {332332- if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED ||333333- sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) {413413+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {414414+ if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {334415 ap_addr->sa_family = ARPHRD_ETHER;335335- memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);336336- return 0;337337- } else {416416+ memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);417417+ } else338418 memset(&ap_addr->sa_data, 0, ETH_ALEN);339339- return 0;340340- }419419+ return 0;420420+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {421421+ if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) {422422+ ap_addr->sa_family = ARPHRD_ETHER;423423+ memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN);424424+ } else425425+ memset(&ap_addr->sa_data, 0, ETH_ALEN);426426+ return 0;341427 } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {342428 ap_addr->sa_family = ARPHRD_ETHER;343429 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);···406486407487 rcu_read_lock();408488409409- sta = sta_info_get(local, sdata->u.sta.bssid);489489+ sta = sta_info_get(local, sdata->u.mgd.bssid);410490411491 if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))412492 rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;···607687 struct iw_mlme *mlme = (struct iw_mlme *) extra;608688609689 sdata = IEEE80211_DEV_TO_SUB_IF(dev);610610- if (sdata->vif.type != NL80211_IFTYPE_STATION &&611611- sdata->vif.type != NL80211_IFTYPE_ADHOC)690690+ if (!(sdata->vif.type == NL80211_IFTYPE_STATION))612691 return -EINVAL;613692614693 switch (mlme->cmd) {···703784 erq->flags |= IW_ENCODE_ENABLED;704785705786 if (sdata->vif.type == NL80211_IFTYPE_STATION) {706706- struct ieee80211_if_sta *ifsta = &sdata->u.sta;707707- switch (ifsta->auth_alg) {787787+ switch (sdata->u.mgd.auth_alg) {708788 case WLAN_AUTH_OPEN:709789 case WLAN_AUTH_LEAP:710790 erq->flags |= IW_ENCODE_OPEN;···767849 ret = ieee80211_hw_config(local,768850 IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);769851770770- if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))852852+ if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))771853 return ret;772854773855 if (conf->dynamic_ps_timeout > 0 &&···826908 if (sdata->vif.type == NL80211_IFTYPE_STATION) {827909 if (data->value & (IW_AUTH_CIPHER_WEP40 |828910 IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))829829- sdata->u.sta.flags |=911911+ sdata->u.mgd.flags |=830912 IEEE80211_STA_TKIP_WEP_USED;831913 else832832- sdata->u.sta.flags &=914914+ sdata->u.mgd.flags &=833915 ~IEEE80211_STA_TKIP_WEP_USED;834916 }835917 break;···840922 if (sdata->vif.type != NL80211_IFTYPE_STATION)841923 ret = -EINVAL;842924 else {843843- sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;925925+ sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;844926 /*845927 * Privacy invoked by wpa_supplicant, store the846928 * value and allow associating to a protected847929 * network without having a key up front.848930 */849931 if (data->value)850850- sdata->u.sta.flags |=932932+ sdata->u.mgd.flags |=851933 IEEE80211_STA_PRIVACY_INVOKED;852934 }853935 break;854936 case IW_AUTH_80211_AUTH_ALG:855855- if (sdata->vif.type == NL80211_IFTYPE_STATION ||856856- sdata->vif.type == NL80211_IFTYPE_ADHOC)857857- sdata->u.sta.auth_algs = data->value;937937+ if (sdata->vif.type == NL80211_IFTYPE_STATION)938938+ sdata->u.mgd.auth_algs = data->value;858939 else859940 ret = -EOPNOTSUPP;860941 break;···862945 ret = -EOPNOTSUPP;863946 break;864947 }865865- if (sdata->vif.type == NL80211_IFTYPE_STATION ||866866- sdata->vif.type == NL80211_IFTYPE_ADHOC) {948948+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {867949 switch (data->value) {868950 case IW_AUTH_MFP_DISABLED:869869- sdata->u.sta.mfp = IEEE80211_MFP_DISABLED;951951+ sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;870952 break;871953 case IW_AUTH_MFP_OPTIONAL:872872- sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL;954954+ sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;873955 break;874956 case IW_AUTH_MFP_REQUIRED:875875- sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED;957957+ sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;876958 break;877959 default:878960 ret = -EINVAL;···886970 return ret;887971}888972973973+static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)974974+{975975+ u8 wstats_flags = 0;976976+977977+ wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |978978+ IEEE80211_HW_SIGNAL_DBM) ?979979+ IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;980980+ wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?981981+ IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;982982+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)983983+ wstats_flags |= IW_QUAL_DBM;984984+985985+ return wstats_flags;986986+}987987+889988/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */890989static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)891990{···911980912981 rcu_read_lock();913982914914- if (sdata->vif.type == NL80211_IFTYPE_STATION ||915915- sdata->vif.type == NL80211_IFTYPE_ADHOC)916916- sta = sta_info_get(local, sdata->u.sta.bssid);983983+ if (sdata->vif.type == NL80211_IFTYPE_STATION)984984+ sta = sta_info_get(local, sdata->u.mgd.bssid);985985+917986 if (!sta) {918987 wstats->discard.fragment = 0;919988 wstats->discard.misc = 0;···94210119431012 switch (data->flags & IW_AUTH_INDEX) {9441013 case IW_AUTH_80211_AUTH_ALG:945945- if (sdata->vif.type == NL80211_IFTYPE_STATION ||946946- sdata->vif.type == NL80211_IFTYPE_ADHOC)947947- data->value = sdata->u.sta.auth_algs;10141014+ if (sdata->vif.type == NL80211_IFTYPE_STATION)10151015+ data->value = sdata->u.mgd.auth_algs;9481016 else9491017 ret = -EOPNOTSUPP;9501018 break;···10461116 (iw_handler) NULL, /* SIOCSIWSENS */10471117 (iw_handler) NULL, /* SIOCGIWSENS */10481118 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */10491049- (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */11191119+ (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */10501120 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */10511121 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */10521122 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
+4-157
net/mac80211/wme.c
···114114{115115 struct ieee80211_master_priv *mpriv = netdev_priv(dev);116116 struct ieee80211_local *local = mpriv->local;117117- struct ieee80211_hw *hw = &local->hw;118117 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;119119- struct sta_info *sta;120118 u16 queue;121119 u8 tid;122120···122124 if (unlikely(queue >= local->hw.queues))123125 queue = local->hw.queues - 1;124126125125- if (skb->requeue) {126126- if (!hw->ampdu_queues)127127- return queue;128128-129129- rcu_read_lock();130130- sta = sta_info_get(local, hdr->addr1);131131- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;132132- if (sta) {133133- int ampdu_queue = sta->tid_to_tx_q[tid];134134-135135- if ((ampdu_queue < ieee80211_num_queues(hw)) &&136136- test_bit(ampdu_queue, local->queue_pool))137137- queue = ampdu_queue;138138- }139139- rcu_read_unlock();140140-141141- return queue;142142- }143143-144144- /* Now we know the 1d priority, fill in the QoS header if145145- * there is one.127127+ /*128128+ * Now we know the 1d priority, fill in the QoS header if129129+ * there is one (and we haven't done this before).146130 */147147- if (ieee80211_is_data_qos(hdr->frame_control)) {131131+ if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) {148132 u8 *p = ieee80211_get_qos_ctl(hdr);149133 u8 ack_policy = 0;150134 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;···136156 /* qos header is 2 bytes, second reserved */137157 *p++ = ack_policy | tid;138158 *p = 0;139139-140140- if (!hw->ampdu_queues)141141- return queue;142142-143143- rcu_read_lock();144144-145145- sta = sta_info_get(local, hdr->addr1);146146- if (sta) {147147- int ampdu_queue = sta->tid_to_tx_q[tid];148148-149149- if ((ampdu_queue < ieee80211_num_queues(hw)) &&150150- test_bit(ampdu_queue, local->queue_pool))151151- queue = ampdu_queue;152152- }153153-154154- rcu_read_unlock();155159 }156160157161 return queue;158158-}159159-160160-int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,161161- struct sta_info *sta, u16 tid)162162-{163163- int i;164164-165165- /* XXX: currently broken due to cb/requeue use */166166- return -EPERM;167167-168168- /* prepare the filter and save it for the SW queue169169- * matching the received HW queue */170170-171171- if (!local->hw.ampdu_queues)172172- return -EPERM;173173-174174- /* try to get a Qdisc from the pool */175175- for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++)176176- if (!test_and_set_bit(i, local->queue_pool)) {177177- ieee80211_stop_queue(local_to_hw(local), i);178178- sta->tid_to_tx_q[tid] = i;179179-180180- /* IF there are already pending packets181181- * on this tid first we need to drain them182182- * on the previous queue183183- * since HT is strict in order */184184-#ifdef CONFIG_MAC80211_HT_DEBUG185185- if (net_ratelimit())186186- printk(KERN_DEBUG "allocated aggregation queue"187187- " %d tid %d addr %pM pool=0x%lX\n",188188- i, tid, sta->sta.addr,189189- local->queue_pool[0]);190190-#endif /* CONFIG_MAC80211_HT_DEBUG */191191- return 0;192192- }193193-194194- return -EAGAIN;195195-}196196-197197-/**198198- * the caller needs to hold netdev_get_tx_queue(local->mdev, X)->lock199199- */200200-void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,201201- struct sta_info *sta, u16 tid,202202- u8 requeue)203203-{204204- int agg_queue = sta->tid_to_tx_q[tid];205205- struct ieee80211_hw *hw = &local->hw;206206-207207- /* return the qdisc to the pool */208208- clear_bit(agg_queue, local->queue_pool);209209- sta->tid_to_tx_q[tid] = ieee80211_num_queues(hw);210210-211211- if (requeue) {212212- ieee80211_requeue(local, agg_queue);213213- } else {214214- struct netdev_queue *txq;215215- spinlock_t *root_lock;216216- struct Qdisc *q;217217-218218- txq = netdev_get_tx_queue(local->mdev, agg_queue);219219- q = rcu_dereference(txq->qdisc);220220- root_lock = qdisc_lock(q);221221-222222- spin_lock_bh(root_lock);223223- qdisc_reset(q);224224- spin_unlock_bh(root_lock);225225- }226226-}227227-228228-void ieee80211_requeue(struct ieee80211_local *local, int queue)229229-{230230- struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue);231231- struct sk_buff_head list;232232- spinlock_t *root_lock;233233- struct Qdisc *qdisc;234234- u32 len;235235-236236- rcu_read_lock_bh();237237-238238- qdisc = rcu_dereference(txq->qdisc);239239- if (!qdisc || !qdisc->dequeue)240240- goto out_unlock;241241-242242- skb_queue_head_init(&list);243243-244244- root_lock = qdisc_root_lock(qdisc);245245- spin_lock(root_lock);246246- for (len = qdisc->q.qlen; len > 0; len--) {247247- struct sk_buff *skb = qdisc->dequeue(qdisc);248248-249249- if (skb)250250- __skb_queue_tail(&list, skb);251251- }252252- spin_unlock(root_lock);253253-254254- for (len = list.qlen; len > 0; len--) {255255- struct sk_buff *skb = __skb_dequeue(&list);256256- u16 new_queue;257257-258258- BUG_ON(!skb);259259- new_queue = ieee80211_select_queue(local->mdev, skb);260260- skb_set_queue_mapping(skb, new_queue);261261-262262- txq = netdev_get_tx_queue(local->mdev, new_queue);263263-264264-265265- qdisc = rcu_dereference(txq->qdisc);266266- root_lock = qdisc_root_lock(qdisc);267267-268268- spin_lock(root_lock);269269- qdisc_enqueue_root(skb, qdisc);270270- spin_unlock(root_lock);271271- }272272-273273-out_unlock:274274- rcu_read_unlock_bh();275162}
···77#include <linux/if.h>88#include <linux/module.h>99#include <linux/err.h>1010-#include <linux/mutex.h>1110#include <linux/list.h>1211#include <linux/nl80211.h>1312#include <linux/debugfs.h>···3031 * only read the list, and that can happen quite3132 * often because we need to do it for each command */3233LIST_HEAD(cfg80211_drv_list);3333-DEFINE_MUTEX(cfg80211_drv_mutex);3434+3535+/*3636+ * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,3737+ * country_ie_regdomain, the reg_beacon_list and the the last regulatory3838+ * request receipt (last_request).3939+ */4040+DEFINE_MUTEX(cfg80211_mutex);34413542/* for debugfs */3643static struct dentry *ieee80211_debugfs_dir;37443838-/* requires cfg80211_drv_mutex to be held! */3939-static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)4545+/* requires cfg80211_mutex to be held! */4646+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)4047{4148 struct cfg80211_registered_device *result = NULL, *drv;42495050+ if (!wiphy_idx_valid(wiphy_idx))5151+ return NULL;5252+5353+ assert_cfg80211_lock();5454+4355 list_for_each_entry(drv, &cfg80211_drv_list, list) {4444- if (drv->idx == wiphy) {5656+ if (drv->wiphy_idx == wiphy_idx) {4557 result = drv;4658 break;4759 }···6151 return result;6252}63535454+int get_wiphy_idx(struct wiphy *wiphy)5555+{5656+ struct cfg80211_registered_device *drv;5757+ if (!wiphy)5858+ return WIPHY_IDX_STALE;5959+ drv = wiphy_to_dev(wiphy);6060+ return drv->wiphy_idx;6161+}6262+6463/* requires cfg80211_drv_mutex to be held! */6464+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)6565+{6666+ struct cfg80211_registered_device *drv;6767+6868+ if (!wiphy_idx_valid(wiphy_idx))6969+ return NULL;7070+7171+ assert_cfg80211_lock();7272+7373+ drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);7474+ if (!drv)7575+ return NULL;7676+ return &drv->wiphy;7777+}7878+7979+/* requires cfg80211_mutex to be held! */6580static struct cfg80211_registered_device *6681__cfg80211_drv_from_info(struct genl_info *info)6782{6883 int ifindex;6969- struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;8484+ struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;7085 struct net_device *dev;7186 int err = -EINVAL;72878888+ assert_cfg80211_lock();8989+7390 if (info->attrs[NL80211_ATTR_WIPHY]) {7474- bywiphy = cfg80211_drv_by_wiphy(9191+ bywiphyidx = cfg80211_drv_by_wiphy_idx(7592 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));7693 err = -ENODEV;7794 }···11578 err = -ENODEV;11679 }11780118118- if (bywiphy && byifidx) {119119- if (bywiphy != byifidx)8181+ if (bywiphyidx && byifidx) {8282+ if (bywiphyidx != byifidx)12083 return ERR_PTR(-EINVAL);12184 else122122- return bywiphy; /* == byifidx */8585+ return bywiphyidx; /* == byifidx */12386 }124124- if (bywiphy)125125- return bywiphy;8787+ if (bywiphyidx)8888+ return bywiphyidx;1268912790 if (byifidx)12891 return byifidx;···13598{13699 struct cfg80211_registered_device *drv;137100138138- mutex_lock(&cfg80211_drv_mutex);101101+ mutex_lock(&cfg80211_mutex);139102 drv = __cfg80211_drv_from_info(info);140103141104 /* if it is not an error we grab the lock on···144107 if (!IS_ERR(drv))145108 mutex_lock(&drv->mtx);146109147147- mutex_unlock(&cfg80211_drv_mutex);110110+ mutex_unlock(&cfg80211_mutex);148111149112 return drv;150113}···155118 struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);156119 struct net_device *dev;157120158158- mutex_lock(&cfg80211_drv_mutex);121121+ mutex_lock(&cfg80211_mutex);159122 dev = dev_get_by_index(&init_net, ifindex);160123 if (!dev)161124 goto out;···166129 drv = ERR_PTR(-ENODEV);167130 dev_put(dev);168131 out:169169- mutex_unlock(&cfg80211_drv_mutex);132132+ mutex_unlock(&cfg80211_mutex);170133 return drv;171134}172135···180143 char *newname)181144{182145 struct cfg80211_registered_device *drv;183183- int idx, taken = -1, result, digits;146146+ int wiphy_idx, taken = -1, result, digits;184147185185- mutex_lock(&cfg80211_drv_mutex);148148+ mutex_lock(&cfg80211_mutex);186149187150 /* prohibit calling the thing phy%d when %d is not its number */188188- sscanf(newname, PHY_NAME "%d%n", &idx, &taken);189189- if (taken == strlen(newname) && idx != rdev->idx) {190190- /* count number of places needed to print idx */151151+ sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);152152+ if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {153153+ /* count number of places needed to print wiphy_idx */191154 digits = 1;192192- while (idx /= 10)155155+ while (wiphy_idx /= 10)193156 digits++;194157 /*195158 * deny the name if it is phy<idx> where <idx> is printed···230193231194 result = 0;232195out_unlock:233233- mutex_unlock(&cfg80211_drv_mutex);196196+ mutex_unlock(&cfg80211_mutex);234197 if (result == 0)235198 nl80211_notify_dev_rename(rdev);236199···257220258221 drv->ops = ops;259222260260- mutex_lock(&cfg80211_drv_mutex);223223+ mutex_lock(&cfg80211_mutex);261224262262- drv->idx = wiphy_counter++;225225+ drv->wiphy_idx = wiphy_counter++;263226264264- if (unlikely(drv->idx < 0)) {227227+ if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {265228 wiphy_counter--;266266- mutex_unlock(&cfg80211_drv_mutex);229229+ mutex_unlock(&cfg80211_mutex);267230 /* ugh, wrapped! */268231 kfree(drv);269232 return NULL;270233 }271234272272- mutex_unlock(&cfg80211_drv_mutex);235235+ mutex_unlock(&cfg80211_mutex);273236274237 /* give it a proper name */275275- dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx);238238+ dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);276239277240 mutex_init(&drv->mtx);278241 mutex_init(&drv->devlist_mtx);···347310 /* check and set up bitrates */348311 ieee80211_set_bitrate_flags(wiphy);349312350350- mutex_lock(&cfg80211_drv_mutex);313313+ mutex_lock(&cfg80211_mutex);351314352315 /* set up regulatory info */353316 wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);···367330368331 res = 0;369332out_unlock:370370- mutex_unlock(&cfg80211_drv_mutex);333333+ mutex_unlock(&cfg80211_mutex);371334 return res;372335}373336EXPORT_SYMBOL(wiphy_register);···377340 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);378341379342 /* protect the device list */380380- mutex_lock(&cfg80211_drv_mutex);343343+ mutex_lock(&cfg80211_mutex);381344382345 BUG_ON(!list_empty(&drv->netdev_list));383346···403366 device_del(&drv->wiphy.dev);404367 debugfs_remove(drv->wiphy.debugfsdir);405368406406- mutex_unlock(&cfg80211_drv_mutex);369369+ mutex_unlock(&cfg80211_mutex);407370}408371EXPORT_SYMBOL(wiphy_unregister);409372
+32-4
net/wireless/core.h
···1010#include <linux/netdevice.h>1111#include <linux/kref.h>1212#include <linux/rbtree.h>1313+#include <linux/mutex.h>1314#include <net/genetlink.h>1415#include <net/wireless.h>1516#include <net/cfg80211.h>···3837 enum environment_cap env;39384039 /* wiphy index, internal only */4141- int idx;4040+ int wiphy_idx;42414342 /* associate netdev list */4443 struct mutex devlist_mtx;···5049 struct rb_root bss_tree;5150 u32 bss_generation;5251 struct cfg80211_scan_request *scan_req; /* protected by RTNL */5252+ unsigned long suspend_at;53535454 /* must be last because of the way we do wiphy_priv(),5555 * and it should at least be aligned to NETDEV_ALIGN */···6462 return container_of(wiphy, struct cfg80211_registered_device, wiphy);6563}66646767-extern struct mutex cfg80211_drv_mutex;6565+/* Note 0 is valid, hence phy0 */6666+static inline6767+bool wiphy_idx_valid(int wiphy_idx)6868+{6969+ return (wiphy_idx >= 0);7070+}7171+7272+extern struct mutex cfg80211_mutex;6873extern struct list_head cfg80211_drv_list;7474+7575+static inline void assert_cfg80211_lock(void)7676+{7777+ WARN_ON(!mutex_is_locked(&cfg80211_mutex));7878+}7979+8080+/*8181+ * You can use this to mark a wiphy_idx as not having an associated wiphy.8282+ * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL8383+ */8484+#define WIPHY_IDX_STALE -169857086struct cfg80211_internal_bss {7187 struct list_head list;···9474 struct cfg80211_bss pub;9575};96767777+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);7878+int get_wiphy_idx(struct wiphy *wiphy);7979+9780/*9881 * This function returns a pointer to the driver9982 * that the genl_info item that is passed refers to.···10481 * the driver's mutex!10582 *10683 * This means that you need to call cfg80211_put_dev()107107- * before being allowed to acquire &cfg80211_drv_mutex!8484+ * before being allowed to acquire &cfg80211_mutex!10885 *10986 * This is necessary because we need to lock the global11087 * mutex to get an item off the list safely, and then11188 * we lock the drv mutex so it doesn't go away under us.11289 *113113- * We don't want to keep cfg80211_drv_mutex locked9090+ * We don't want to keep cfg80211_mutex locked11491 * for all the time in order to allow requests on11592 * other interfaces to go through at the same time.11693 *···11996 */12097extern struct cfg80211_registered_device *12198cfg80211_get_dev_from_info(struct genl_info *info);9999+100100+/* requires cfg80211_drv_mutex to be held! */101101+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);122102123103/* identical to cfg80211_get_dev_from_info but only operate on ifindex */124104extern struct cfg80211_registered_device *···139113void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);140114141115void cfg80211_bss_expire(struct cfg80211_registered_device *dev);116116+void cfg80211_bss_age(struct cfg80211_registered_device *dev,117117+ unsigned long age_secs);142118143119#endif /* __NET_WIRELESS_CORE_H */
+53-22
net/wireless/nl80211.c
···77#include <linux/if.h>88#include <linux/module.h>99#include <linux/err.h>1010-#include <linux/mutex.h>1110#include <linux/list.h>1211#include <linux/if_ether.h>1312#include <linux/ieee80211.h>···141142 if (!hdr)142143 return -1;143144144144- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);145145+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);145146 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));146147 NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,147148 dev->wiphy.max_scan_ssids);···255256 int start = cb->args[0];256257 struct cfg80211_registered_device *dev;257258258258- mutex_lock(&cfg80211_drv_mutex);259259+ mutex_lock(&cfg80211_mutex);259260 list_for_each_entry(dev, &cfg80211_drv_list, list) {260261 if (++idx <= start)261262 continue;···266267 break;267268 }268269 }269269- mutex_unlock(&cfg80211_drv_mutex);270270+ mutex_unlock(&cfg80211_mutex);270271271272 cb->args[0] = idx;272273···469470 struct cfg80211_registered_device *dev;470471 struct wireless_dev *wdev;471472472472- mutex_lock(&cfg80211_drv_mutex);473473+ mutex_lock(&cfg80211_mutex);473474 list_for_each_entry(dev, &cfg80211_drv_list, list) {474475 if (wp_idx < wp_start) {475476 wp_idx++;···496497 wp_idx++;497498 }498499 out:499499- mutex_unlock(&cfg80211_drv_mutex);500500+ mutex_unlock(&cfg80211_mutex);500501501502 cb->args[0] = wp_idx;502503 cb->args[1] = if_idx;···1205120612061207 nla_nest_end(msg, txrate);12071208 }12091209+ if (sinfo->filled & STATION_INFO_RX_PACKETS)12101210+ NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,12111211+ sinfo->rx_packets);12121212+ if (sinfo->filled & STATION_INFO_TX_PACKETS)12131213+ NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,12141214+ sinfo->tx_packets);12081215 nla_nest_end(msg, sinfoattr);1209121612101217 return genlmsg_end(msg, hdr);···19051900 int r;19061901 char *data = NULL;1907190219031903+ /*19041904+ * You should only get this when cfg80211 hasn't yet initialized19051905+ * completely when built-in to the kernel right between the time19061906+ * window between nl80211_init() and regulatory_init(), if that is19071907+ * even possible.19081908+ */19091909+ mutex_lock(&cfg80211_mutex);19101910+ if (unlikely(!cfg80211_regdomain)) {19111911+ mutex_unlock(&cfg80211_mutex);19121912+ return -EINPROGRESS;19131913+ }19141914+ mutex_unlock(&cfg80211_mutex);19151915+19081916 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])19091917 return -EINVAL;19101918···19281910 if (is_world_regdom(data))19291911 return -EINVAL;19301912#endif19311931- mutex_lock(&cfg80211_drv_mutex);19321932- r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);19331933- mutex_unlock(&cfg80211_drv_mutex);19341934- /* This means the regulatory domain was already set, however19351935- * we don't want to confuse userspace with a "successful error"19361936- * message so lets just treat it as a success */19371937- if (r == -EALREADY)19381938- r = 0;19131913+19141914+ r = regulatory_hint_user(data);19151915+19391916 return r;19401917}19411918···21192106 unsigned int i;21202107 int err = -EINVAL;2121210821222122- mutex_lock(&cfg80211_drv_mutex);21092109+ mutex_lock(&cfg80211_mutex);2123211021242111 if (!cfg80211_regdomain)21252112 goto out;···21822169 genlmsg_cancel(msg, hdr);21832170 err = -EMSGSIZE;21842171out:21852185- mutex_unlock(&cfg80211_drv_mutex);21722172+ mutex_unlock(&cfg80211_mutex);21862173 return err;21872174}21882175···2241222822422229 BUG_ON(rule_idx != num_rules);2243223022442244- mutex_lock(&cfg80211_drv_mutex);22312231+ mutex_lock(&cfg80211_mutex);22452232 r = set_regdom(rd);22462246- mutex_unlock(&cfg80211_drv_mutex);22332233+ mutex_unlock(&cfg80211_mutex);22472234 return r;2248223522492236 bad_reg:···22992286 struct wiphy *wiphy;23002287 int err, tmp, n_ssids = 0, n_channels = 0, i;23012288 enum ieee80211_band band;22892289+ size_t ie_len;2302229023032291 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);23042292 if (err)···23412327 goto out_unlock;23422328 }2343232923302330+ if (info->attrs[NL80211_ATTR_IE])23312331+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);23322332+ else23332333+ ie_len = 0;23342334+23442335 request = kzalloc(sizeof(*request)23452336 + sizeof(*ssid) * n_ssids23462346- + sizeof(channel) * n_channels, GFP_KERNEL);23372337+ + sizeof(channel) * n_channels23382338+ + ie_len, GFP_KERNEL);23472339 if (!request) {23482340 err = -ENOMEM;23492341 goto out_unlock;···23602340 if (n_ssids)23612341 request->ssids = (void *)(request->channels + n_channels);23622342 request->n_ssids = n_ssids;23432343+ if (ie_len) {23442344+ if (request->ssids)23452345+ request->ie = (void *)(request->ssids + n_ssids);23462346+ else23472347+ request->ie = (void *)(request->channels + n_channels);23482348+ }2363234923642350 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {23652351 /* user specified, bail out if channel not found */···24042378 request->ssids[i].ssid_len = nla_len(attr);24052379 i++;24062380 }23812381+ }23822382+23832383+ if (info->attrs[NL80211_ATTR_IE]) {23842384+ request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);23852385+ memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),23862386+ request->ie_len);24072387 }2408238824092389 request->ifidx = dev->ifindex;···24642432 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);24652433 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);2466243424672467- switch (res->signal_type) {24352435+ switch (rdev->wiphy.signal_type) {24682436 case CFG80211_SIGNAL_TYPE_MBM:24692437 NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);24702438 break;···26332601 .doit = nl80211_get_station,26342602 .dumpit = nl80211_dump_station,26352603 .policy = nl80211_policy,26362636- .flags = GENL_ADMIN_PERM,26372604 },26382605 {26392606 .cmd = NL80211_CMD_SET_STATION,···27702739 if (!hdr)27712740 return -1;2772274127732773- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);27422742+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);27742743 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);2775274427762745 /* XXX: we should probably bounce back the request? */
···5454 MHZ_TO_KHZ(20),5555};56565757-/* Central wireless core regulatory domains, we only need two,5757+/*5858+ * Central wireless core regulatory domains, we only need two,5859 * the current one and a world regulatory domain in case we have no5959- * information to give us an alpha2 */6060+ * information to give us an alpha26161+ */6062const struct ieee80211_regdomain *cfg80211_regdomain;61636262-/* We use this as a place for the rd structure built from the6464+/*6565+ * We use this as a place for the rd structure built from the6366 * last parsed country IE to rest until CRDA gets back to us with6464- * what it thinks should apply for the same country */6767+ * what it thinks should apply for the same country6868+ */6569static const struct ieee80211_regdomain *country_ie_regdomain;7070+7171+/* Used to queue up regulatory hints */7272+static LIST_HEAD(reg_requests_list);7373+static spinlock_t reg_requests_lock;7474+7575+/* Used to queue up beacon hints for review */7676+static LIST_HEAD(reg_pending_beacons);7777+static spinlock_t reg_pending_beacons_lock;7878+7979+/* Used to keep track of processed beacon hints */8080+static LIST_HEAD(reg_beacon_list);8181+8282+struct reg_beacon {8383+ struct list_head list;8484+ struct ieee80211_channel chan;8585+};66866787/* We keep a static world regulatory domain in case of the absence of CRDA */6888static const struct ieee80211_regdomain world_regdom = {6969- .n_reg_rules = 1,8989+ .n_reg_rules = 3,7090 .alpha2 = "00",7191 .reg_rules = {7272- REG_RULE(2412-10, 2462+10, 40, 6, 20,9292+ /* IEEE 802.11b/g, channels 1..11 */9393+ REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),9494+ /* IEEE 802.11a, channel 36..48 */9595+ REG_RULE(5180-10, 5240+10, 40, 6, 23,9696+ NL80211_RRF_PASSIVE_SCAN |9797+ NL80211_RRF_NO_IBSS),9898+9999+ /* NB: 5260 MHz - 5700 MHz requies DFS */100100+101101+ /* IEEE 802.11a, channel 149..165 */102102+ REG_RULE(5745-10, 5825+10, 40, 6, 23,73103 NL80211_RRF_PASSIVE_SCAN |74104 NL80211_RRF_NO_IBSS),75105 }···11383module_param(ieee80211_regdom, charp, 0444);11484MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");11585116116-/* We assume 40 MHz bandwidth for the old regulatory work.8686+/*8787+ * We assume 40 MHz bandwidth for the old regulatory work.11788 * We make emphasis we are using the exact same frequencies118118- * as before */8989+ * as before9090+ */1199112092static const struct ieee80211_regdomain us_regdom = {12193 .n_reg_rules = 6,···156124157125static const struct ieee80211_regdomain eu_regdom = {158126 .n_reg_rules = 6,159159- /* This alpha2 is bogus, we leave it here just for stupid160160- * backward compatibility */127127+ /*128128+ * This alpha2 is bogus, we leave it here just for stupid129129+ * backward compatibility130130+ */161131 .alpha2 = "EU",162132 .reg_rules = {163133 /* IEEE 802.11b/g, channels 1..13 */···228194 cfg80211_regdomain = NULL;229195}230196231231-/* Dynamic world regulatory domain requested by the wireless232232- * core upon initialization */197197+/*198198+ * Dynamic world regulatory domain requested by the wireless199199+ * core upon initialization200200+ */233201static void update_world_regdomain(const struct ieee80211_regdomain *rd)234202{235203 BUG_ON(!last_request);···272236{273237 if (!alpha2)274238 return false;275275- /* Special case where regulatory domain was built by driver276276- * but a specific alpha2 cannot be determined */239239+ /*240240+ * Special case where regulatory domain was built by driver241241+ * but a specific alpha2 cannot be determined242242+ */277243 if (alpha2[0] == '9' && alpha2[1] == '9')278244 return true;279245 return false;···285247{286248 if (!alpha2)287249 return false;288288- /* Special case where regulatory domain is the250250+ /*251251+ * Special case where regulatory domain is the289252 * result of an intersection between two regulatory domain290290- * structures */253253+ * structures254254+ */291255 if (alpha2[0] == '9' && alpha2[1] == '8')292256 return true;293257 return false;···314274 return false;315275}316276317317-static bool regdom_changed(const char *alpha2)277277+static bool regdom_changes(const char *alpha2)318278{279279+ assert_cfg80211_lock();280280+319281 if (!cfg80211_regdomain)320282 return true;321283 if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))···344302 return false;345303}346304347347-/* This lets us keep regulatory code which is updated on a regulatory348348- * basis in userspace. */305305+/*306306+ * This lets us keep regulatory code which is updated on a regulatory307307+ * basis in userspace.308308+ */349309static int call_crda(const char *alpha2)350310{351311 char country_env[9 + 2] = "COUNTRY=";···458414#undef ONE_GHZ_IN_KHZ459415}460416461461-/* Converts a country IE to a regulatory domain. A regulatory domain417417+/*418418+ * Converts a country IE to a regulatory domain. A regulatory domain462419 * structure has a lot of information which the IE doesn't yet have,463420 * so for the other values we use upper max values as we will intersect464464- * with our userspace regulatory agent to get lower bounds. */421421+ * with our userspace regulatory agent to get lower bounds.422422+ */465423static struct ieee80211_regdomain *country_ie_2_rd(466424 u8 *country_ie,467425 u8 country_ie_len,···508462509463 *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);510464511511- /* We need to build a reg rule for each triplet, but first we must465465+ /*466466+ * We need to build a reg rule for each triplet, but first we must512467 * calculate the number of reg rules we will need. We will need one513513- * for each channel subband */468468+ * for each channel subband469469+ */514470 while (country_ie_len >= 3) {515471 int end_channel = 0;516472 struct ieee80211_country_ie_triplet *triplet =···550502 if (cur_sub_max_channel < cur_channel)551503 return NULL;552504553553- /* Do not allow overlapping channels. Also channels505505+ /*506506+ * Do not allow overlapping channels. Also channels554507 * passed in each subband must be monotonically555555- * increasing */508508+ * increasing509509+ */556510 if (last_sub_max_channel) {557511 if (cur_channel <= last_sub_max_channel)558512 return NULL;···562512 return NULL;563513 }564514565565- /* When dot11RegulatoryClassesRequired is supported515515+ /*516516+ * When dot11RegulatoryClassesRequired is supported566517 * we can throw ext triplets as part of this soup,567518 * for now we don't care when those change as we568568- * don't support them */519519+ * don't support them520520+ */569521 *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |570522 ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |571523 ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);···578526 country_ie_len -= 3;579527 num_rules++;580528581581- /* Note: this is not a IEEE requirement but582582- * simply a memory requirement */529529+ /*530530+ * Note: this is not a IEEE requirement but531531+ * simply a memory requirement532532+ */583533 if (num_rules > NL80211_MAX_SUPP_REG_RULES)584534 return NULL;585535 }···609555 struct ieee80211_freq_range *freq_range = NULL;610556 struct ieee80211_power_rule *power_rule = NULL;611557612612- /* Must parse if dot11RegulatoryClassesRequired is true,613613- * we don't support this yet */558558+ /*559559+ * Must parse if dot11RegulatoryClassesRequired is true,560560+ * we don't support this yet561561+ */614562 if (triplet->ext.reg_extension_id >=615563 IEEE80211_COUNTRY_EXTENSION_ID) {616564 country_ie += 3;···634578 end_channel = triplet->chans.first_channel +635579 (4 * (triplet->chans.num_channels - 1));636580637637- /* The +10 is since the regulatory domain expects581581+ /*582582+ * The +10 is since the regulatory domain expects638583 * the actual band edge, not the center of freq for639584 * its start and end freqs, assuming 20 MHz bandwidth on640640- * the channels passed */585585+ * the channels passed586586+ */641587 freq_range->start_freq_khz =642588 MHZ_TO_KHZ(ieee80211_channel_to_frequency(643589 triplet->chans.first_channel) - 10);···647589 MHZ_TO_KHZ(ieee80211_channel_to_frequency(648590 end_channel) + 10);649591650650- /* Large arbitrary values, we intersect later */651651- /* Increment this if we ever support >= 40 MHz channels652652- * in IEEE 802.11 */592592+ /*593593+ * These are large arbitrary values we use to intersect later.594594+ * Increment this if we ever support >= 40 MHz channels595595+ * in IEEE 802.11596596+ */653597 freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);654598 power_rule->max_antenna_gain = DBI_TO_MBI(100);655599 power_rule->max_eirp = DBM_TO_MBM(100);···667607}668608669609670670-/* Helper for regdom_intersect(), this does the real671671- * mathematical intersection fun */610610+/*611611+ * Helper for regdom_intersect(), this does the real612612+ * mathematical intersection fun613613+ */672614static int reg_rules_intersect(673615 const struct ieee80211_reg_rule *rule1,674616 const struct ieee80211_reg_rule *rule2,···748686 if (!rd1 || !rd2)749687 return NULL;750688751751- /* First we get a count of the rules we'll need, then we actually689689+ /*690690+ * First we get a count of the rules we'll need, then we actually752691 * build them. This is to so we can malloc() and free() a753692 * regdomain once. The reason we use reg_rules_intersect() here754693 * is it will return -EINVAL if the rule computed makes no sense.755755- * All rules that do check out OK are valid. */694694+ * All rules that do check out OK are valid.695695+ */756696757697 for (x = 0; x < rd1->n_reg_rules; x++) {758698 rule1 = &rd1->reg_rules[x];···782718 rule1 = &rd1->reg_rules[x];783719 for (y = 0; y < rd2->n_reg_rules; y++) {784720 rule2 = &rd2->reg_rules[y];785785- /* This time around instead of using the stack lets721721+ /*722722+ * This time around instead of using the stack lets786723 * write to the target rule directly saving ourselves787787- * a memcpy() */724724+ * a memcpy()725725+ */788726 intersected_rule = &rd->reg_rules[rule_idx];789727 r = reg_rules_intersect(rule1, rule2,790728 intersected_rule);791791- /* No need to memset here the intersected rule here as792792- * we're not using the stack anymore */729729+ /*730730+ * No need to memset here the intersected rule here as731731+ * we're not using the stack anymore732732+ */793733 if (r)794734 continue;795735 rule_idx++;···812744 return rd;813745}814746815815-/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may816816- * want to just have the channel structure use these */747747+/*748748+ * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may749749+ * want to just have the channel structure use these750750+ */817751static u32 map_regdom_flags(u32 rd_flags)818752{819753 u32 channel_flags = 0;···841771842772 regd = custom_regd ? custom_regd : cfg80211_regdomain;843773844844- /* Follow the driver's regulatory domain, if present, unless a country845845- * IE has been processed or a user wants to help complaince further */774774+ /*775775+ * Follow the driver's regulatory domain, if present, unless a country776776+ * IE has been processed or a user wants to help complaince further777777+ */846778 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&847779 last_request->initiator != REGDOM_SET_BY_USER &&848780 wiphy->regd)···862790 fr = &rr->freq_range;863791 pr = &rr->power_rule;864792865865- /* We only need to know if one frequency rule was793793+ /*794794+ * We only need to know if one frequency rule was866795 * was in center_freq's band, that's enough, so lets867867- * not overwrite it once found */796796+ * not overwrite it once found797797+ */868798 if (!band_rule_found)869799 band_rule_found = freq_in_rule_band(fr, center_freq);870800···903829 const struct ieee80211_power_rule *power_rule = NULL;904830 struct ieee80211_supported_band *sband;905831 struct ieee80211_channel *chan;832832+ struct wiphy *request_wiphy = NULL;833833+834834+ assert_cfg80211_lock();835835+836836+ request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);906837907838 sband = wiphy->bands[band];908839 BUG_ON(chan_idx >= sband->n_channels);···919840 &max_bandwidth, ®_rule);920841921842 if (r) {922922- /* This means no regulatory rule was found in the country IE843843+ /*844844+ * This means no regulatory rule was found in the country IE923845 * with a frequency range on the center_freq's band, since924846 * IEEE-802.11 allows for a country IE to have a subset of the925847 * regulatory information provided in a country we ignore···939859 chan->center_freq, wiphy_name(wiphy));940860#endif941861 } else {942942- /* In this case we know the country IE has at least one reg rule943943- * for the band so we respect its band definitions */862862+ /*863863+ * In this case we know the country IE has at least one reg rule864864+ * for the band so we respect its band definitions865865+ */944866#ifdef CONFIG_CFG80211_REG_DEBUG945867 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)946868 printk(KERN_DEBUG "cfg80211: Disabling "···959877 power_rule = ®_rule->power_rule;960878961879 if (last_request->initiator == REGDOM_SET_BY_DRIVER &&962962- last_request->wiphy && last_request->wiphy == wiphy &&963963- last_request->wiphy->strict_regulatory) {964964- /* This gaurantees the driver's requested regulatory domain880880+ request_wiphy && request_wiphy == wiphy &&881881+ request_wiphy->strict_regulatory) {882882+ /*883883+ * This gaurantees the driver's requested regulatory domain965884 * will always be used as a base for further regulatory966966- * settings */885885+ * settings886886+ */967887 chan->flags = chan->orig_flags =968888 map_regdom_flags(reg_rule->flags);969889 chan->max_antenna_gain = chan->orig_mag =···1006922 if (setby == REGDOM_SET_BY_CORE &&1007923 wiphy->custom_regulatory)1008924 return true;10091009- /* wiphy->regd will be set once the device has its own10101010- * desired regulatory domain set */925925+ /*926926+ * wiphy->regd will be set once the device has its own927927+ * desired regulatory domain set928928+ */1011929 if (wiphy->strict_regulatory && !wiphy->regd &&1012930 !is_world_regdom(last_request->alpha2))1013931 return true;···1024938 wiphy_update_regulatory(&drv->wiphy, setby);1025939}1026940941941+static void handle_reg_beacon(struct wiphy *wiphy,942942+ unsigned int chan_idx,943943+ struct reg_beacon *reg_beacon)944944+{945945+#ifdef CONFIG_CFG80211_REG_DEBUG946946+#define REG_DEBUG_BEACON_FLAG(desc) \947947+ printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \948948+ "frequency: %d MHz (Ch %d) on %s\n", \949949+ reg_beacon->chan.center_freq, \950950+ ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \951951+ wiphy_name(wiphy));952952+#else953953+#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0)954954+#endif955955+ struct ieee80211_supported_band *sband;956956+ struct ieee80211_channel *chan;957957+958958+ assert_cfg80211_lock();959959+960960+ sband = wiphy->bands[reg_beacon->chan.band];961961+ chan = &sband->channels[chan_idx];962962+963963+ if (likely(chan->center_freq != reg_beacon->chan.center_freq))964964+ return;965965+966966+ if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {967967+ chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;968968+ REG_DEBUG_BEACON_FLAG("active scanning");969969+ }970970+971971+ if (chan->flags & IEEE80211_CHAN_NO_IBSS) {972972+ chan->flags &= ~IEEE80211_CHAN_NO_IBSS;973973+ REG_DEBUG_BEACON_FLAG("beaconing");974974+ }975975+976976+ chan->beacon_found = true;977977+#undef REG_DEBUG_BEACON_FLAG978978+}979979+980980+/*981981+ * Called when a scan on a wiphy finds a beacon on982982+ * new channel983983+ */984984+static void wiphy_update_new_beacon(struct wiphy *wiphy,985985+ struct reg_beacon *reg_beacon)986986+{987987+ unsigned int i;988988+ struct ieee80211_supported_band *sband;989989+990990+ assert_cfg80211_lock();991991+992992+ if (!wiphy->bands[reg_beacon->chan.band])993993+ return;994994+995995+ sband = wiphy->bands[reg_beacon->chan.band];996996+997997+ for (i = 0; i < sband->n_channels; i++)998998+ handle_reg_beacon(wiphy, i, reg_beacon);999999+}10001000+10011001+/*10021002+ * Called upon reg changes or a new wiphy is added10031003+ */10041004+static void wiphy_update_beacon_reg(struct wiphy *wiphy)10051005+{10061006+ unsigned int i;10071007+ struct ieee80211_supported_band *sband;10081008+ struct reg_beacon *reg_beacon;10091009+10101010+ assert_cfg80211_lock();10111011+10121012+ if (list_empty(®_beacon_list))10131013+ return;10141014+10151015+ list_for_each_entry(reg_beacon, ®_beacon_list, list) {10161016+ if (!wiphy->bands[reg_beacon->chan.band])10171017+ continue;10181018+ sband = wiphy->bands[reg_beacon->chan.band];10191019+ for (i = 0; i < sband->n_channels; i++)10201020+ handle_reg_beacon(wiphy, i, reg_beacon);10211021+ }10221022+}10231023+10241024+static bool reg_is_world_roaming(struct wiphy *wiphy)10251025+{10261026+ if (is_world_regdom(cfg80211_regdomain->alpha2) ||10271027+ (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))10281028+ return true;10291029+ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&10301030+ wiphy->custom_regulatory)10311031+ return true;10321032+ return false;10331033+}10341034+10351035+/* Reap the advantages of previously found beacons */10361036+static void reg_process_beacons(struct wiphy *wiphy)10371037+{10381038+ if (!reg_is_world_roaming(wiphy))10391039+ return;10401040+ wiphy_update_beacon_reg(wiphy);10411041+}10421042+10271043void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)10281044{10291045 enum ieee80211_band band;1030104610311047 if (ignore_reg_update(wiphy, setby))10321032- return;10481048+ goto out;10331049 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {10341050 if (wiphy->bands[band])10351051 handle_band(wiphy, band);10361052 }10531053+out:10541054+ reg_process_beacons(wiphy);10371055 if (wiphy->reg_notifier)10381056 wiphy->reg_notifier(wiphy, last_request);10391057}···12231033 return 0;12241034}1225103512261226-/* Return value which can be used by ignore_request() to indicate12271227- * it has been determined we should intersect two regulatory domains */10361036+/*10371037+ * Return value which can be used by ignore_request() to indicate10381038+ * it has been determined we should intersect two regulatory domains10391039+ */12281040#define REG_INTERSECT 11229104112301042/* This has the logic which determines when a new request12311043 * should be ignored. */12321232-static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,12331233- const char *alpha2)10441044+static int ignore_request(struct wiphy *wiphy,10451045+ struct regulatory_request *pending_request)12341046{10471047+ struct wiphy *last_wiphy = NULL;10481048+10491049+ assert_cfg80211_lock();10501050+12351051 /* All initial requests are respected */12361052 if (!last_request)12371053 return 0;1238105412391239- switch (set_by) {10551055+ switch (pending_request->initiator) {12401056 case REGDOM_SET_BY_INIT:12411057 return -EINVAL;12421058 case REGDOM_SET_BY_CORE:12431243- /*12441244- * Always respect new wireless core hints, should only happen12451245- * when updating the world regulatory domain at init.12461246- */12471247- return 0;10591059+ return -EINVAL;12481060 case REGDOM_SET_BY_COUNTRY_IE:12491249- if (unlikely(!is_an_alpha2(alpha2)))10611061+10621062+ last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);10631063+10641064+ if (unlikely(!is_an_alpha2(pending_request->alpha2)))12501065 return -EINVAL;12511066 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {12521252- if (last_request->wiphy != wiphy) {10671067+ if (last_wiphy != wiphy) {12531068 /*12541069 * Two cards with two APs claiming different12551070 * different Country IE alpha2s. We could12561071 * intersect them, but that seems unlikely12571072 * to be correct. Reject second one for now.12581073 */12591259- if (!alpha2_equal(alpha2,12601260- cfg80211_regdomain->alpha2))10741074+ if (regdom_changes(pending_request->alpha2))12611075 return -EOPNOTSUPP;12621076 return -EALREADY;12631077 }12641264- /* Two consecutive Country IE hints on the same wiphy.12651265- * This should be picked up early by the driver/stack */12661266- if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,12671267- alpha2)))10781078+ /*10791079+ * Two consecutive Country IE hints on the same wiphy.10801080+ * This should be picked up early by the driver/stack10811081+ */10821082+ if (WARN_ON(regdom_changes(pending_request->alpha2)))12681083 return 0;12691084 return -EALREADY;12701085 }···12781083 if (last_request->initiator == REGDOM_SET_BY_CORE) {12791084 if (is_old_static_regdom(cfg80211_regdomain))12801085 return 0;12811281- if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))10861086+ if (regdom_changes(pending_request->alpha2))12821087 return 0;12831088 return -EALREADY;12841089 }10901090+10911091+ /*10921092+ * This would happen if you unplug and plug your card10931093+ * back in or if you add a new device for which the previously10941094+ * loaded card also agrees on the regulatory domain.10951095+ */10961096+ if (last_request->initiator == REGDOM_SET_BY_DRIVER &&10971097+ !regdom_changes(pending_request->alpha2))10981098+ return -EALREADY;10991099+12851100 return REG_INTERSECT;12861101 case REGDOM_SET_BY_USER:12871102 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)12881103 return REG_INTERSECT;12891289- /* If the user knows better the user should set the regdom12901290- * to their country before the IE is picked up */11041104+ /*11051105+ * If the user knows better the user should set the regdom11061106+ * to their country before the IE is picked up11071107+ */12911108 if (last_request->initiator == REGDOM_SET_BY_USER &&12921109 last_request->intersect)12931110 return -EOPNOTSUPP;12941294- /* Process user requests only after previous user/driver/core12951295- * requests have been processed */11111111+ /*11121112+ * Process user requests only after previous user/driver/core11131113+ * requests have been processed11141114+ */12961115 if (last_request->initiator == REGDOM_SET_BY_CORE ||12971116 last_request->initiator == REGDOM_SET_BY_DRIVER ||12981117 last_request->initiator == REGDOM_SET_BY_USER) {12991299- if (!alpha2_equal(last_request->alpha2,13001300- cfg80211_regdomain->alpha2))11181118+ if (regdom_changes(last_request->alpha2))13011119 return -EAGAIN;13021120 }1303112113041122 if (!is_old_static_regdom(cfg80211_regdomain) &&13051305- alpha2_equal(cfg80211_regdomain->alpha2, alpha2))11231123+ !regdom_changes(pending_request->alpha2))13061124 return -EALREADY;1307112513081126 return 0;···13241116 return -EINVAL;13251117}1326111813271327-/* Caller must hold &cfg80211_drv_mutex */13281328-int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,13291329- const char *alpha2,13301330- u32 country_ie_checksum,13311331- enum environment_cap env)11191119+/**11201120+ * __regulatory_hint - hint to the wireless core a regulatory domain11211121+ * @wiphy: if the hint comes from country information from an AP, this11221122+ * is required to be set to the wiphy that received the information11231123+ * @pending_request: the regulatory request currently being processed11241124+ *11251125+ * The Wireless subsystem can use this function to hint to the wireless core11261126+ * what it believes should be the current regulatory domain.11271127+ *11281128+ * Returns zero if all went fine, %-EALREADY if a regulatory domain had11291129+ * already been set or other standard error codes.11301130+ *11311131+ * Caller must hold &cfg80211_mutex11321132+ */11331133+static int __regulatory_hint(struct wiphy *wiphy,11341134+ struct regulatory_request *pending_request)13321135{13331333- struct regulatory_request *request;13341136 bool intersect = false;13351137 int r = 0;1336113813371337- r = ignore_request(wiphy, set_by, alpha2);11391139+ assert_cfg80211_lock();11401140+11411141+ r = ignore_request(wiphy, pending_request);1338114213391143 if (r == REG_INTERSECT) {13401340- if (set_by == REGDOM_SET_BY_DRIVER) {11441144+ if (pending_request->initiator == REGDOM_SET_BY_DRIVER) {13411145 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);13421342- if (r)11461146+ if (r) {11471147+ kfree(pending_request);13431148 return r;11491149+ }13441150 }13451151 intersect = true;13461152 } else if (r) {13471347- /* If the regulatory domain being requested by the11531153+ /*11541154+ * If the regulatory domain being requested by the13481155 * driver has already been set just copy it to the13491349- * wiphy */13501350- if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {11561156+ * wiphy11571157+ */11581158+ if (r == -EALREADY &&11591159+ pending_request->initiator == REGDOM_SET_BY_DRIVER) {13511160 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);13521352- if (r)11611161+ if (r) {11621162+ kfree(pending_request);13531163 return r;11641164+ }13541165 r = -EALREADY;13551166 goto new_request;13561167 }11681168+ kfree(pending_request);13571169 return r;13581170 }1359117113601172new_request:13611361- request = kzalloc(sizeof(struct regulatory_request),13621362- GFP_KERNEL);13631363- if (!request)13641364- return -ENOMEM;13651365-13661366- request->alpha2[0] = alpha2[0];13671367- request->alpha2[1] = alpha2[1];13681368- request->initiator = set_by;13691369- request->wiphy = wiphy;13701370- request->intersect = intersect;13711371- request->country_ie_checksum = country_ie_checksum;13721372- request->country_ie_env = env;13731373-13741173 kfree(last_request);13751375- last_request = request;11741174+11751175+ last_request = pending_request;11761176+ last_request->intersect = intersect;11771177+11781178+ pending_request = NULL;1376117913771180 /* When r == REG_INTERSECT we do need to call CRDA */13781181 if (r < 0)···13991180 *14001181 * to intersect with the static rd14011182 */14021402- return call_crda(alpha2);11831183+ return call_crda(last_request->alpha2);14031184}1404118514051405-void regulatory_hint(struct wiphy *wiphy, const char *alpha2)11861186+/* This currently only processes user and driver regulatory hints */11871187+static void reg_process_hint(struct regulatory_request *reg_request)14061188{14071407- int r;11891189+ int r = 0;11901190+ struct wiphy *wiphy = NULL;11911191+11921192+ BUG_ON(!reg_request->alpha2);11931193+11941194+ mutex_lock(&cfg80211_mutex);11951195+11961196+ if (wiphy_idx_valid(reg_request->wiphy_idx))11971197+ wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);11981198+11991199+ if (reg_request->initiator == REGDOM_SET_BY_DRIVER &&12001200+ !wiphy) {12011201+ kfree(reg_request);12021202+ goto out;12031203+ }12041204+12051205+ r = __regulatory_hint(wiphy, reg_request);12061206+ /* This is required so that the orig_* parameters are saved */12071207+ if (r == -EALREADY && wiphy && wiphy->strict_regulatory)12081208+ wiphy_update_regulatory(wiphy, reg_request->initiator);12091209+out:12101210+ mutex_unlock(&cfg80211_mutex);12111211+}12121212+12131213+/* Processes regulatory hints, this is all the REGDOM_SET_BY_* */12141214+static void reg_process_pending_hints(void)12151215+ {12161216+ struct regulatory_request *reg_request;12171217+12181218+ spin_lock(®_requests_lock);12191219+ while (!list_empty(®_requests_list)) {12201220+ reg_request = list_first_entry(®_requests_list,12211221+ struct regulatory_request,12221222+ list);12231223+ list_del_init(®_request->list);12241224+12251225+ spin_unlock(®_requests_lock);12261226+ reg_process_hint(reg_request);12271227+ spin_lock(®_requests_lock);12281228+ }12291229+ spin_unlock(®_requests_lock);12301230+}12311231+12321232+/* Processes beacon hints -- this has nothing to do with country IEs */12331233+static void reg_process_pending_beacon_hints(void)12341234+{12351235+ struct cfg80211_registered_device *drv;12361236+ struct reg_beacon *pending_beacon, *tmp;12371237+12381238+ mutex_lock(&cfg80211_mutex);12391239+12401240+ /* This goes through the _pending_ beacon list */12411241+ spin_lock_bh(®_pending_beacons_lock);12421242+12431243+ if (list_empty(®_pending_beacons)) {12441244+ spin_unlock_bh(®_pending_beacons_lock);12451245+ goto out;12461246+ }12471247+12481248+ list_for_each_entry_safe(pending_beacon, tmp,12491249+ ®_pending_beacons, list) {12501250+12511251+ list_del_init(&pending_beacon->list);12521252+12531253+ /* Applies the beacon hint to current wiphys */12541254+ list_for_each_entry(drv, &cfg80211_drv_list, list)12551255+ wiphy_update_new_beacon(&drv->wiphy, pending_beacon);12561256+12571257+ /* Remembers the beacon hint for new wiphys or reg changes */12581258+ list_add_tail(&pending_beacon->list, ®_beacon_list);12591259+ }12601260+12611261+ spin_unlock_bh(®_pending_beacons_lock);12621262+out:12631263+ mutex_unlock(&cfg80211_mutex);12641264+}12651265+12661266+static void reg_todo(struct work_struct *work)12671267+{12681268+ reg_process_pending_hints();12691269+ reg_process_pending_beacon_hints();12701270+}12711271+12721272+static DECLARE_WORK(reg_work, reg_todo);12731273+12741274+static void queue_regulatory_request(struct regulatory_request *request)12751275+{12761276+ spin_lock(®_requests_lock);12771277+ list_add_tail(&request->list, ®_requests_list);12781278+ spin_unlock(®_requests_lock);12791279+12801280+ schedule_work(®_work);12811281+}12821282+12831283+/* Core regulatory hint -- happens once during cfg80211_init() */12841284+static int regulatory_hint_core(const char *alpha2)12851285+{12861286+ struct regulatory_request *request;12871287+12881288+ BUG_ON(last_request);12891289+12901290+ request = kzalloc(sizeof(struct regulatory_request),12911291+ GFP_KERNEL);12921292+ if (!request)12931293+ return -ENOMEM;12941294+12951295+ request->alpha2[0] = alpha2[0];12961296+ request->alpha2[1] = alpha2[1];12971297+ request->initiator = REGDOM_SET_BY_CORE;12981298+12991299+ queue_regulatory_request(request);13001300+13011301+ return 0;13021302+}13031303+13041304+/* User hints */13051305+int regulatory_hint_user(const char *alpha2)13061306+{13071307+ struct regulatory_request *request;13081308+14081309 BUG_ON(!alpha2);1409131014101410- mutex_lock(&cfg80211_drv_mutex);14111411- r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,14121412- alpha2, 0, ENVIRON_ANY);14131413- /* This is required so that the orig_* parameters are saved */14141414- if (r == -EALREADY && wiphy->strict_regulatory)14151415- wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);14161416- mutex_unlock(&cfg80211_drv_mutex);13111311+ request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);13121312+ if (!request)13131313+ return -ENOMEM;13141314+13151315+ request->wiphy_idx = WIPHY_IDX_STALE;13161316+ request->alpha2[0] = alpha2[0];13171317+ request->alpha2[1] = alpha2[1];13181318+ request->initiator = REGDOM_SET_BY_USER,13191319+13201320+ queue_regulatory_request(request);13211321+13221322+ return 0;13231323+}13241324+13251325+/* Driver hints */13261326+int regulatory_hint(struct wiphy *wiphy, const char *alpha2)13271327+{13281328+ struct regulatory_request *request;13291329+13301330+ BUG_ON(!alpha2);13311331+ BUG_ON(!wiphy);13321332+13331333+ request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);13341334+ if (!request)13351335+ return -ENOMEM;13361336+13371337+ request->wiphy_idx = get_wiphy_idx(wiphy);13381338+13391339+ /* Must have registered wiphy first */13401340+ BUG_ON(!wiphy_idx_valid(request->wiphy_idx));13411341+13421342+ request->alpha2[0] = alpha2[0];13431343+ request->alpha2[1] = alpha2[1];13441344+ request->initiator = REGDOM_SET_BY_DRIVER;13451345+13461346+ queue_regulatory_request(request);13471347+13481348+ return 0;14171349}14181350EXPORT_SYMBOL(regulatory_hint);1419135114201352static bool reg_same_country_ie_hint(struct wiphy *wiphy,14211353 u32 country_ie_checksum)14221354{14231423- if (!last_request->wiphy)13551355+ struct wiphy *request_wiphy;13561356+13571357+ assert_cfg80211_lock();13581358+13591359+ request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);13601360+13611361+ if (!request_wiphy)14241362 return false;14251425- if (likely(last_request->wiphy != wiphy))13631363+13641364+ if (likely(request_wiphy != wiphy))14261365 return !country_ie_integrity_changes(country_ie_checksum);14271427- /* We should not have let these through at this point, they13661366+ /*13671367+ * We should not have let these through at this point, they14281368 * should have been picked up earlier by the first alpha2 check14291429- * on the device */13691369+ * on the device13701370+ */14301371 if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))14311372 return true;14321373 return false;···16001221 char alpha2[2];16011222 u32 checksum = 0;16021223 enum environment_cap env = ENVIRON_ANY;12241224+ struct regulatory_request *request;1603122516041604- if (!last_request)12261226+ mutex_lock(&cfg80211_mutex);12271227+12281228+ if (unlikely(!last_request)) {12291229+ mutex_unlock(&cfg80211_mutex);16051230 return;16061606-16071607- mutex_lock(&cfg80211_drv_mutex);12311231+ }1608123216091233 /* IE len must be evenly divisible by 2 */16101234 if (country_ie_len & 0x01)···16161234 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)16171235 goto out;1618123616191619- /* Pending country IE processing, this can happen after we12371237+ /*12381238+ * Pending country IE processing, this can happen after we16201239 * call CRDA and wait for a response if a beacon was received before16211621- * we were able to process the last regulatory_hint_11d() call */12401240+ * we were able to process the last regulatory_hint_11d() call12411241+ */16221242 if (country_ie_regdomain)16231243 goto out;16241244···16321248 else if (country_ie[2] == 'O')16331249 env = ENVIRON_OUTDOOR;1634125016351635- /* We will run this for *every* beacon processed for the BSSID, so12511251+ /*12521252+ * We will run this for *every* beacon processed for the BSSID, so16361253 * we optimize an early check to exit out early if we don't have to16371637- * do anything */16381638- if (likely(last_request->wiphy)) {12541254+ * do anything12551255+ */12561256+ if (likely(wiphy_idx_valid(last_request->wiphy_idx))) {16391257 struct cfg80211_registered_device *drv_last_ie;1640125816411641- drv_last_ie = wiphy_to_dev(last_request->wiphy);12591259+ drv_last_ie =12601260+ cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);1642126116431643- /* Lets keep this simple -- we trust the first AP16441644- * after we intersect with CRDA */16451645- if (likely(last_request->wiphy == wiphy)) {16461646- /* Ignore IEs coming in on this wiphy with16471647- * the same alpha2 and environment cap */12621262+ /*12631263+ * Lets keep this simple -- we trust the first AP12641264+ * after we intersect with CRDA12651265+ */12661266+ if (likely(&drv_last_ie->wiphy == wiphy)) {12671267+ /*12681268+ * Ignore IEs coming in on this wiphy with12691269+ * the same alpha2 and environment cap12701270+ */16481271 if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,16491272 alpha2) &&16501273 env == drv_last_ie->env)) {16511274 goto out;16521275 }16531653- /* the wiphy moved on to another BSSID or the AP12761276+ /*12771277+ * the wiphy moved on to another BSSID or the AP16541278 * was reconfigured. XXX: We need to deal with the16551279 * case where the user suspends and goes to goes16561280 * to another country, and then gets IEs from an16571657- * AP with different settings */12811281+ * AP with different settings12821282+ */16581283 goto out;16591284 } else {16601660- /* Ignore IEs coming in on two separate wiphys with16611661- * the same alpha2 and environment cap */12851285+ /*12861286+ * Ignore IEs coming in on two separate wiphys with12871287+ * the same alpha2 and environment cap12881288+ */16621289 if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,16631290 alpha2) &&16641291 env == drv_last_ie->env)) {···16841289 if (!rd)16851290 goto out;1686129116871687- /* This will not happen right now but we leave it here for the12921292+ /*12931293+ * This will not happen right now but we leave it here for the16881294 * the future when we want to add suspend/resume support and having16891295 * the user move to another country after doing so, or having the user16901690- * move to another AP. Right now we just trust the first AP. This is why16911691- * this is marked as likley(). If we hit this before we add this support16921692- * we want to be informed of it as it would indicate a mistake in the16931693- * current design */16941694- if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))16951695- goto out;12961296+ * move to another AP. Right now we just trust the first AP.12971297+ *12981298+ * If we hit this before we add this support we want to be informed of12991299+ * it as it would indicate a mistake in the current design13001300+ */13011301+ if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))13021302+ goto free_rd_out;1696130316971697- /* We keep this around for when CRDA comes back with a response so16981698- * we can intersect with that */13041304+ request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);13051305+ if (!request)13061306+ goto free_rd_out;13071307+13081308+ /*13091309+ * We keep this around for when CRDA comes back with a response so13101310+ * we can intersect with that13111311+ */16991312 country_ie_regdomain = rd;1700131317011701- __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,17021702- country_ie_regdomain->alpha2, checksum, env);13141314+ request->wiphy_idx = get_wiphy_idx(wiphy);13151315+ request->alpha2[0] = rd->alpha2[0];13161316+ request->alpha2[1] = rd->alpha2[1];13171317+ request->initiator = REGDOM_SET_BY_COUNTRY_IE;13181318+ request->country_ie_checksum = checksum;13191319+ request->country_ie_env = env;1703132013211321+ mutex_unlock(&cfg80211_mutex);13221322+13231323+ queue_regulatory_request(request);13241324+13251325+ return;13261326+13271327+free_rd_out:13281328+ kfree(rd);17041329out:17051705- mutex_unlock(&cfg80211_drv_mutex);13301330+ mutex_unlock(&cfg80211_mutex);17061331}17071332EXPORT_SYMBOL(regulatory_hint_11d);13331333+13341334+static bool freq_is_chan_12_13_14(u16 freq)13351335+{13361336+ if (freq == ieee80211_channel_to_frequency(12) ||13371337+ freq == ieee80211_channel_to_frequency(13) ||13381338+ freq == ieee80211_channel_to_frequency(14))13391339+ return true;13401340+ return false;13411341+}13421342+13431343+int regulatory_hint_found_beacon(struct wiphy *wiphy,13441344+ struct ieee80211_channel *beacon_chan,13451345+ gfp_t gfp)13461346+{13471347+ struct reg_beacon *reg_beacon;13481348+13491349+ if (likely((beacon_chan->beacon_found ||13501350+ (beacon_chan->flags & IEEE80211_CHAN_RADAR) ||13511351+ (beacon_chan->band == IEEE80211_BAND_2GHZ &&13521352+ !freq_is_chan_12_13_14(beacon_chan->center_freq)))))13531353+ return 0;13541354+13551355+ reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp);13561356+ if (!reg_beacon)13571357+ return -ENOMEM;13581358+13591359+#ifdef CONFIG_CFG80211_REG_DEBUG13601360+ printk(KERN_DEBUG "cfg80211: Found new beacon on "13611361+ "frequency: %d MHz (Ch %d) on %s\n",13621362+ beacon_chan->center_freq,13631363+ ieee80211_frequency_to_channel(beacon_chan->center_freq),13641364+ wiphy_name(wiphy));13651365+#endif13661366+ memcpy(®_beacon->chan, beacon_chan,13671367+ sizeof(struct ieee80211_channel));13681368+13691369+13701370+ /*13711371+ * Since we can be called from BH or and non-BH context13721372+ * we must use spin_lock_bh()13731373+ */13741374+ spin_lock_bh(®_pending_beacons_lock);13751375+ list_add_tail(®_beacon->list, ®_pending_beacons);13761376+ spin_unlock_bh(®_pending_beacons_lock);13771377+13781378+ schedule_work(®_work);13791379+13801380+ return 0;13811381+}1708138217091383static void print_rd_rules(const struct ieee80211_regdomain *rd)17101384{···17901326 freq_range = ®_rule->freq_range;17911327 power_rule = ®_rule->power_rule;1792132817931793- /* There may not be documentation for max antenna gain17941794- * in certain regions */13291329+ /*13301330+ * There may not be documentation for max antenna gain13311331+ * in certain regions13321332+ */17951333 if (power_rule->max_antenna_gain)17961334 printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "17971335 "(%d mBi, %d mBm)\n",···18161350{1817135118181352 if (is_intersected_alpha2(rd->alpha2)) {18191819- struct wiphy *wiphy = NULL;18201820- struct cfg80211_registered_device *drv;1821135318221354 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {18231823- if (last_request->wiphy) {18241824- wiphy = last_request->wiphy;18251825- drv = wiphy_to_dev(wiphy);13551355+ struct cfg80211_registered_device *drv;13561356+ drv = cfg80211_drv_by_wiphy_idx(13571357+ last_request->wiphy_idx);13581358+ if (drv) {18261359 printk(KERN_INFO "cfg80211: Current regulatory "18271360 "domain updated by AP to: %c%c\n",18281361 drv->country_ie_alpha2[0],···18871422{18881423 const struct ieee80211_regdomain *intersected_rd = NULL;18891424 struct cfg80211_registered_device *drv = NULL;18901890- struct wiphy *wiphy = NULL;14251425+ struct wiphy *request_wiphy;18911426 /* Some basic sanity checks first */1892142718931428 if (is_world_regdom(rd->alpha2)) {···19041439 if (!last_request)19051440 return -EINVAL;1906144119071907- /* Lets only bother proceeding on the same alpha2 if the current14421442+ /*14431443+ * Lets only bother proceeding on the same alpha2 if the current19081444 * rd is non static (it means CRDA was present and was used last)19091909- * and the pending request came in from a country IE */14451445+ * and the pending request came in from a country IE14461446+ */19101447 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {19111911- /* If someone else asked us to change the rd lets only bother19121912- * checking if the alpha2 changes if CRDA was already called */14481448+ /*14491449+ * If someone else asked us to change the rd lets only bother14501450+ * checking if the alpha2 changes if CRDA was already called14511451+ */19131452 if (!is_old_static_regdom(cfg80211_regdomain) &&19141914- !regdom_changed(rd->alpha2))14531453+ !regdom_changes(rd->alpha2))19151454 return -EINVAL;19161455 }1917145619181918- wiphy = last_request->wiphy;19191919-19201920- /* Now lets set the regulatory domain, update all driver channels14571457+ /*14581458+ * Now lets set the regulatory domain, update all driver channels19211459 * and finally inform them of what we have done, in case they want19221460 * to review or adjust their own settings based on their own19231923- * internal EEPROM data */14611461+ * internal EEPROM data14621462+ */1924146319251464 if (WARN_ON(!reg_is_valid_request(rd->alpha2)))19261465 return -EINVAL;···19361467 return -EINVAL;19371468 }1938146914701470+ request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);14711471+19391472 if (!last_request->intersect) {19401473 int r;19411474···19471476 return 0;19481477 }1949147819501950- /* For a driver hint, lets copy the regulatory domain the19511951- * driver wanted to the wiphy to deal with conflicts */14791479+ /*14801480+ * For a driver hint, lets copy the regulatory domain the14811481+ * driver wanted to the wiphy to deal with conflicts14821482+ */1952148319531953- BUG_ON(last_request->wiphy->regd);14841484+ BUG_ON(request_wiphy->regd);1954148519551955- r = reg_copy_regd(&last_request->wiphy->regd, rd);14861486+ r = reg_copy_regd(&request_wiphy->regd, rd);19561487 if (r)19571488 return r;19581489···19711498 if (!intersected_rd)19721499 return -EINVAL;1973150019741974- /* We can trash what CRDA provided now.15011501+ /*15021502+ * We can trash what CRDA provided now.19751503 * However if a driver requested this specific regulatory19761976- * domain we keep it for its private use */15041504+ * domain we keep it for its private use15051505+ */19771506 if (last_request->initiator == REGDOM_SET_BY_DRIVER)19781978- last_request->wiphy->regd = rd;15071507+ request_wiphy->regd = rd;19791508 else19801509 kfree(rd);19811510···19971522 BUG_ON(!country_ie_regdomain);1998152319991524 if (rd != country_ie_regdomain) {20002000- /* Intersect what CRDA returned and our what we20012001- * had built from the Country IE received */15251525+ /*15261526+ * Intersect what CRDA returned and our what we15271527+ * had built from the Country IE received15281528+ */2002152920031530 intersected_rd = regdom_intersect(rd, country_ie_regdomain);20041531···20101533 kfree(country_ie_regdomain);20111534 country_ie_regdomain = NULL;20121535 } else {20132013- /* This would happen when CRDA was not present and15361536+ /*15371537+ * This would happen when CRDA was not present and20141538 * OLD_REGULATORY was enabled. We intersect our Country20152015- * IE rd and what was set on cfg80211 originally */15391539+ * IE rd and what was set on cfg80211 originally15401540+ */20161541 intersected_rd = regdom_intersect(rd, cfg80211_regdomain);20171542 }2018154320191544 if (!intersected_rd)20201545 return -EINVAL;2021154620222022- drv = wiphy_to_dev(wiphy);15471547+ drv = wiphy_to_dev(request_wiphy);2023154820241549 drv->country_ie_alpha2[0] = rd->alpha2[0];20251550 drv->country_ie_alpha2[1] = rd->alpha2[1];···20391560}204015612041156220422042-/* Use this call to set the current regulatory domain. Conflicts with15631563+/*15641564+ * Use this call to set the current regulatory domain. Conflicts with20431565 * multiple drivers can be ironed out later. Caller must've already20442044- * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */15661566+ * kmalloc'd the rd structure. Caller must hold cfg80211_mutex15671567+ */20451568int set_regdom(const struct ieee80211_regdomain *rd)20461569{20471570 int r;15711571+15721572+ assert_cfg80211_lock();2048157320491574 /* Note that this doesn't update the wiphys, this is done below */20501575 r = __set_regdom(rd);···20691586 return r;20701587}2071158820722072-/* Caller must hold cfg80211_drv_mutex */15891589+/* Caller must hold cfg80211_mutex */20731590void reg_device_remove(struct wiphy *wiphy)20741591{15921592+ struct wiphy *request_wiphy;15931593+15941594+ assert_cfg80211_lock();15951595+15961596+ request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);15971597+20751598 kfree(wiphy->regd);20762076- if (!last_request || !last_request->wiphy)15991599+ if (!last_request || !request_wiphy)20771600 return;20782078- if (last_request->wiphy != wiphy)16011601+ if (request_wiphy != wiphy)20791602 return;20802080- last_request->wiphy = NULL;16031603+ last_request->wiphy_idx = WIPHY_IDX_STALE;20811604 last_request->country_ie_env = ENVIRON_ANY;20821605}2083160620841607int regulatory_init(void)20851608{20862086- int err;16091609+ int err = 0;2087161020881611 reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);20891612 if (IS_ERR(reg_pdev))20901613 return PTR_ERR(reg_pdev);16141614+16151615+ spin_lock_init(®_requests_lock);16161616+ spin_lock_init(®_pending_beacons_lock);2091161720921618#ifdef CONFIG_WIRELESS_OLD_REGULATORY20931619 cfg80211_regdomain = static_regdom(ieee80211_regdom);2094162020951621 printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");20961622 print_regdomain_info(cfg80211_regdomain);20972097- /* The old code still requests for a new regdomain and if16231623+ /*16241624+ * The old code still requests for a new regdomain and if20981625 * you have CRDA you get it updated, otherwise you get20991626 * stuck with the static values. We ignore "EU" code as21002100- * that is not a valid ISO / IEC 3166 alpha2 */16271627+ * that is not a valid ISO / IEC 3166 alpha216281628+ */21011629 if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')21022102- err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,21032103- ieee80211_regdom, 0, ENVIRON_ANY);16301630+ err = regulatory_hint_core(ieee80211_regdom);21041631#else21051632 cfg80211_regdomain = cfg80211_world_regdom;2106163321072107- err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);21082108- if (err)21092109- printk(KERN_ERR "cfg80211: calling CRDA failed - "21102110- "unable to update world regulatory domain, "21112111- "using static definition\n");16341634+ err = regulatory_hint_core("00");21121635#endif16361636+ if (err) {16371637+ if (err == -ENOMEM)16381638+ return err;16391639+ /*16401640+ * N.B. kobject_uevent_env() can fail mainly for when we're out16411641+ * memory which is handled and propagated appropriately above16421642+ * but it can also fail during a netlink_broadcast() or during16431643+ * early boot for call_usermodehelper(). For now treat these16441644+ * errors as non-fatal.16451645+ */16461646+ printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable "16471647+ "to call CRDA during init");16481648+#ifdef CONFIG_CFG80211_REG_DEBUG16491649+ /* We want to find out exactly why when debugging */16501650+ WARN_ON(err);16511651+#endif16521652+ }2113165321141654 return 0;21151655}2116165621171657void regulatory_exit(void)21181658{21192119- mutex_lock(&cfg80211_drv_mutex);16591659+ struct regulatory_request *reg_request, *tmp;16601660+ struct reg_beacon *reg_beacon, *btmp;16611661+16621662+ cancel_work_sync(®_work);16631663+16641664+ mutex_lock(&cfg80211_mutex);2120166521211666 reset_regdomains();21221667···2155164421561645 platform_device_unregister(reg_pdev);2157164621582158- mutex_unlock(&cfg80211_drv_mutex);16471647+ spin_lock_bh(®_pending_beacons_lock);16481648+ if (!list_empty(®_pending_beacons)) {16491649+ list_for_each_entry_safe(reg_beacon, btmp,16501650+ ®_pending_beacons, list) {16511651+ list_del(®_beacon->list);16521652+ kfree(reg_beacon);16531653+ }16541654+ }16551655+ spin_unlock_bh(®_pending_beacons_lock);16561656+16571657+ if (!list_empty(®_beacon_list)) {16581658+ list_for_each_entry_safe(reg_beacon, btmp,16591659+ ®_beacon_list, list) {16601660+ list_del(®_beacon->list);16611661+ kfree(reg_beacon);16621662+ }16631663+ }16641664+16651665+ spin_lock(®_requests_lock);16661666+ if (!list_empty(®_requests_list)) {16671667+ list_for_each_entry_safe(reg_request, tmp,16681668+ ®_requests_list, list) {16691669+ list_del(®_request->list);16701670+ kfree(reg_request);16711671+ }16721672+ }16731673+ spin_unlock(®_requests_lock);16741674+16751675+ mutex_unlock(&cfg80211_mutex);21591676}
+18-18
net/wireless/reg.h
···66bool is_world_regdom(const char *alpha2);77bool reg_is_valid_request(const char *alpha2);8899+int regulatory_hint_user(const char *alpha2);1010+911void reg_device_remove(struct wiphy *wiphy);10121113int regulatory_init(void);···1614int set_regdom(const struct ieee80211_regdomain *rd);17151816/**1919- * __regulatory_hint - hint to the wireless core a regulatory domain2020- * @wiphy: if the hint comes from country information from an AP, this2121- * is required to be set to the wiphy that received the information2222- * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain2323- * should be in.2424- * @country_ie_checksum: checksum of processed country IE, set this to 02525- * if the hint did not come from a country IE2626- * @country_ie_env: the environment the IE told us we are in, %ENVIRON_*1717+ * regulatory_hint_found_beacon - hints a beacon was found on a channel1818+ * @wiphy: the wireless device where the beacon was found on1919+ * @beacon_chan: the channel on which the beacon was found on2020+ * @gfp: context flags2721 *2828- * The Wireless subsystem can use this function to hint to the wireless core2929- * what it believes should be the current regulatory domain by giving it an3030- * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be3131- * in.2222+ * This informs the wireless core that a beacon from an AP was found on2323+ * the channel provided. This allows the wireless core to make educated2424+ * guesses on regulatory to help with world roaming. This is only used for2525+ * world roaming -- when we do not know our current location. This is2626+ * only useful on channels 12, 13 and 14 on the 2 GHz band as channels2727+ * 1-11 are already enabled by the world regulatory domain; and on2828+ * non-radar 5 GHz channels.3229 *3333- * Returns zero if all went fine, %-EALREADY if a regulatory domain had3434- * already been set or other standard error codes.3535- *3030+ * Drivers do not need to call this, cfg80211 will do it for after a scan3131+ * on a newly found BSS.3632 */3737-extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,3838- const char *alpha2, u32 country_ie_checksum,3939- enum environment_cap country_ie_env);3333+int regulatory_hint_found_beacon(struct wiphy *wiphy,3434+ struct ieee80211_channel *beacon_chan,3535+ gfp_t gfp);40364137#endif /* __NET_WIRELESS_REG_H */
+47-17
net/wireless/scan.c
···6262}63636464/* must hold dev->bss_lock! */6565+void cfg80211_bss_age(struct cfg80211_registered_device *dev,6666+ unsigned long age_secs)6767+{6868+ struct cfg80211_internal_bss *bss;6969+ unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);7070+7171+ list_for_each_entry(bss, &dev->bss_list, list) {7272+ bss->ts -= age_jiffies;7373+ }7474+}7575+7676+/* must hold dev->bss_lock! */6577void cfg80211_bss_expire(struct cfg80211_registered_device *dev)6678{6779 struct cfg80211_internal_bss *bss, *tmp;···370358 found->pub.beacon_interval = res->pub.beacon_interval;371359 found->pub.tsf = res->pub.tsf;372360 found->pub.signal = res->pub.signal;373373- found->pub.signal_type = res->pub.signal_type;374361 found->pub.capability = res->pub.capability;375362 found->ts = res->ts;376363 kref_put(&res->ref, bss_release);···391380cfg80211_inform_bss_frame(struct wiphy *wiphy,392381 struct ieee80211_channel *channel,393382 struct ieee80211_mgmt *mgmt, size_t len,394394- s32 signal, enum cfg80211_signal_type sigtype,395395- gfp_t gfp)383383+ s32 signal, gfp_t gfp)396384{397385 struct cfg80211_internal_bss *res;398386 size_t ielen = len - offsetof(struct ieee80211_mgmt,···399389 bool overwrite;400390 size_t privsz = wiphy->bss_priv_size;401391402402- if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&392392+ if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&403393 (signal < 0 || signal > 100)))404394 return NULL;405395···413403414404 memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);415405 res->pub.channel = channel;416416- res->pub.signal_type = sigtype;417406 res->pub.signal = signal;418407 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);419408 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);···429420 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);430421 if (!res)431422 return NULL;423423+424424+ if (res->pub.capability & WLAN_CAPABILITY_ESS)425425+ regulatory_hint_found_beacon(wiphy, channel, gfp);432426433427 /* cfg80211_bss_update gives us a referenced result */434428 return &res->pub;···596584 }597585}598586587587+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)588588+{589589+ unsigned long end = jiffies;590590+591591+ if (end >= start)592592+ return jiffies_to_msecs(end - start);593593+594594+ return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);595595+}599596600597static char *601601-ieee80211_bss(struct iw_request_info *info,602602- struct cfg80211_internal_bss *bss,603603- char *current_ev, char *end_buf)598598+ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,599599+ struct cfg80211_internal_bss *bss, char *current_ev,600600+ char *end_buf)604601{605602 struct iw_event iwe;606603 u8 *buf, *cfg, *p;607604 u8 *ie = bss->pub.information_elements;608608- int rem = bss->pub.len_information_elements, i;605605+ int rem = bss->pub.len_information_elements, i, sig;609606 bool ismesh = false;610607611608 memset(&iwe, 0, sizeof(iwe));···638617 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,639618 IW_EV_FREQ_LEN);640619641641- if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {620620+ if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {642621 memset(&iwe, 0, sizeof(iwe));643622 iwe.cmd = IWEVQUAL;644623 iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |645624 IW_QUAL_NOISE_INVALID |646646- IW_QUAL_QUAL_INVALID;647647- switch (bss->pub.signal_type) {625625+ IW_QUAL_QUAL_UPDATED;626626+ switch (wiphy->signal_type) {648627 case CFG80211_SIGNAL_TYPE_MBM:649649- iwe.u.qual.level = bss->pub.signal / 100;628628+ sig = bss->pub.signal / 100;629629+ iwe.u.qual.level = sig;650630 iwe.u.qual.updated |= IW_QUAL_DBM;631631+ if (sig < -110) /* rather bad */632632+ sig = -110;633633+ else if (sig > -40) /* perfect */634634+ sig = -40;635635+ /* will give a range of 0 .. 70 */636636+ iwe.u.qual.qual = sig + 110;651637 break;652638 case CFG80211_SIGNAL_TYPE_UNSPEC:653639 iwe.u.qual.level = bss->pub.signal;640640+ /* will give range 0 .. 100 */641641+ iwe.u.qual.qual = bss->pub.signal;654642 break;655643 default:656644 /* not reached */···793763 &iwe, buf);794764 memset(&iwe, 0, sizeof(iwe));795765 iwe.cmd = IWEVCUSTOM;796796- sprintf(buf, " Last beacon: %dms ago",797797- jiffies_to_msecs(jiffies - bss->ts));766766+ sprintf(buf, " Last beacon: %ums ago",767767+ elapsed_jiffies_msecs(bss->ts));798768 iwe.u.data.length = strlen(buf);799769 current_ev = iwe_stream_add_point(info, current_ev,800770 end_buf, &iwe, buf);···823793 spin_unlock_bh(&dev->bss_lock);824794 return -E2BIG;825795 }826826- current_ev = ieee80211_bss(info, bss,827827- current_ev, end_buf);796796+ current_ev = ieee80211_bss(&dev->wiphy, info, bss,797797+ current_ev, end_buf);828798 }829799 spin_unlock_bh(&dev->bss_lock);830800 return current_ev - buf;
+8-1
net/wireless/sysfs.c
···3131 return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \3232}33333434-SHOW_FMT(index, "%d", idx);3434+SHOW_FMT(index, "%d", wiphy_idx);3535SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);36363737static struct device_attribute ieee80211_dev_attrs[] = {···6060 struct cfg80211_registered_device *rdev = dev_to_rdev(dev);6161 int ret = 0;62626363+ rdev->suspend_at = get_seconds();6464+6365 if (rdev->ops->suspend) {6466 rtnl_lock();6567 ret = rdev->ops->suspend(&rdev->wiphy);···7573{7674 struct cfg80211_registered_device *rdev = dev_to_rdev(dev);7775 int ret = 0;7676+7777+ /* Age scan results with time spent in suspend */7878+ spin_lock_bh(&rdev->bss_lock);7979+ cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at);8080+ spin_unlock_bh(&rdev->bss_lock);78817982 if (rdev->ops->resume) {8083 rtnl_lock();