add updated mac80211 - this no longer relies on patching includes in the kernel trees...
authorFelix Fietkau <nbd@openwrt.org>
Sat, 13 Oct 2007 22:41:08 +0000 (22:41 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 13 Oct 2007 22:41:08 +0000 (22:41 +0000)
SVN-Revision: 9290

52 files changed:
package/mac80211/Makefile
package/mac80211/src/include/linux/ieee80211.h [new file with mode: 0644]
package/mac80211/src/include/linux/nl80211.h [new file with mode: 0644]
package/mac80211/src/include/net/cfg80211.h [new file with mode: 0644]
package/mac80211/src/include/net/ieee80211_radiotap.h [new file with mode: 0644]
package/mac80211/src/include/net/mac80211.h [new file with mode: 0644]
package/mac80211/src/mac80211/Kconfig
package/mac80211/src/mac80211/Makefile
package/mac80211/src/mac80211/cfg.c [new file with mode: 0644]
package/mac80211/src/mac80211/cfg.h [new file with mode: 0644]
package/mac80211/src/mac80211/debugfs.c
package/mac80211/src/mac80211/debugfs_key.c
package/mac80211/src/mac80211/debugfs_netdev.c
package/mac80211/src/mac80211/debugfs_sta.c
package/mac80211/src/mac80211/event.c [new file with mode: 0644]
package/mac80211/src/mac80211/hostapd_ioctl.h [deleted file]
package/mac80211/src/mac80211/ieee80211.c
package/mac80211/src/mac80211/ieee80211_cfg.c [deleted file]
package/mac80211/src/mac80211/ieee80211_cfg.h [deleted file]
package/mac80211/src/mac80211/ieee80211_common.h
package/mac80211/src/mac80211/ieee80211_i.h
package/mac80211/src/mac80211/ieee80211_iface.c
package/mac80211/src/mac80211/ieee80211_ioctl.c
package/mac80211/src/mac80211/ieee80211_key.h
package/mac80211/src/mac80211/ieee80211_led.c
package/mac80211/src/mac80211/ieee80211_led.h
package/mac80211/src/mac80211/ieee80211_rate.c
package/mac80211/src/mac80211/ieee80211_rate.h
package/mac80211/src/mac80211/ieee80211_sta.c
package/mac80211/src/mac80211/key.c [new file with mode: 0644]
package/mac80211/src/mac80211/rc80211_lowest.c [deleted file]
package/mac80211/src/mac80211/rc80211_simple.c
package/mac80211/src/mac80211/regdomain.c
package/mac80211/src/mac80211/rx.c [new file with mode: 0644]
package/mac80211/src/mac80211/sta_info.c
package/mac80211/src/mac80211/sta_info.h
package/mac80211/src/mac80211/tkip.c
package/mac80211/src/mac80211/tkip.h
package/mac80211/src/mac80211/tx.c [new file with mode: 0644]
package/mac80211/src/mac80211/util.c [new file with mode: 0644]
package/mac80211/src/mac80211/wep.c
package/mac80211/src/mac80211/wep.h
package/mac80211/src/mac80211/wme.c
package/mac80211/src/mac80211/wme.h
package/mac80211/src/mac80211/wpa.c
package/mac80211/src/mac80211/wpa.h
package/mac80211/src/wireless/Makefile
package/mac80211/src/wireless/core.c
package/mac80211/src/wireless/nl80211.c
package/mac80211/src/wireless/radiotap.c [new file with mode: 0644]
package/mac80211/src/wireless/sysfs.c
package/mac80211/src/wireless/wext.c [deleted file]

index 416507f9ed7122420b44e890b1c5dd9cc16b0e98..1898998a1e4b51b79bf13ab8643c1952d400caad 100644 (file)
@@ -21,58 +21,59 @@ define KernelPackage/mac80211
   SUBMENU:=Wireless Drivers
   TITLE:=Linux 802.11 Wireless Networking Stack
   DEPENDS:=@LINUX_2_6 +kmod-crypto-arc4 +kmod-crypto-aes
-  KCONFIG:=CONFIG_MAC80211
   FILES:= \
        $(PKG_BUILD_DIR)/mac80211/mac80211.$(LINUX_KMOD_SUFFIX) \
-       $(PKG_BUILD_DIR)/mac80211/rc80211_lowest.$(LINUX_KMOD_SUFFIX) \
        $(PKG_BUILD_DIR)/mac80211/rc80211_simple.$(LINUX_KMOD_SUFFIX) \
        $(PKG_BUILD_DIR)/wireless/cfg80211.$(LINUX_KMOD_SUFFIX)
   AUTOLOAD:=$(call AutoLoad,20,cfg80211 mac80211 rc80211_simple)
 endef
 
 define KernelPackage/mac80211/description
- This package contains the DeviceScape 80211 wireless stack.
+Linux 802.11 Wireless Networking Stack
 endef
 
-define Build/Prepare
-       mkdir -p $(PKG_BUILD_DIR)/mac80211
-       $(CP) ./src/mac80211/* $(PKG_BUILD_DIR)/mac80211/
-       mkdir -p $(PKG_BUILD_DIR)/wireless
-       $(CP) ./src/wireless/* $(PKG_BUILD_DIR)/wireless/
-endef
+CONFOPTS:=MAC80211 CFG80211 NL80211
 
-ifneq ($(CONFIG_MAC80211),)
+BUILDFLAGS:= \
+       $(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) ) \
+       $(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS)
 
-  MAKE_OPTS:= \
+MAKE_OPTS:= \
        CROSS_COMPILE="$(TARGET_CROSS)" \
        ARCH="$(LINUX_KARCH)" \
-       EXTRA_CFLAGS="$(BUILDFLAGS) -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS" \
-       CONFIG_MAC80211=m \
+       EXTRA_CFLAGS="$(BUILDFLAGS)" \
+       $(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \
        CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \
+       LINUXINCLUDE="-I${CURDIR}/src/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \
+       V=1
+
+
+ifneq ($(findstring 2.6.23,$(LINUX_VERSION)),)
+  define Build/Prepare
+       mkdir -p $(PKG_BUILD_DIR)/mac80211
+       $(CP) ./src/mac80211/* $(PKG_BUILD_DIR)/mac80211/
+       mkdir -p $(PKG_BUILD_DIR)/wireless
+       $(CP) ./src/wireless/* $(PKG_BUILD_DIR)/wireless/
+  endef
 
-  define Build/Compile/it
+  define Build/Compile
        $(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/wireless" modules
        $(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) SUBDIRS="$(PKG_BUILD_DIR)/mac80211" modules
   endef
 
-endif
-
-define Build/Compile
-       $(call Build/Compile/it)
-endef
-
-define Build/InstallDev
+  define Build/InstallDev
        mkdir -p $(1)/usr/include/mac80211
-       $(CP) $(PKG_BUILD_DIR)/mac80211/{hostapd_ioctl,ieee80211_common}.h $(1)/usr/include/mac80211/
-endef
+       $(CP) ./src/include $(1)/usr/include/mac80211/
+  endef
 
-define Build/UninstallDev
+  define Build/UninstallDev
        rm -rf  $(1)/usr/include/mac80211
-endef
+  endef
 
-define KernelPackage/mac80211/install
+  define KernelPackage/mac80211/install
        $(INSTALL_DIR) $(1)/lib/wifi
        $(INSTALL_DATA) ./files/lib/wifi/mac80211.sh $(1)/lib/wifi
-endef
+  endef
+endif
 
 $(eval $(call KernelPackage,mac80211))
diff --git a/package/mac80211/src/include/linux/ieee80211.h b/package/mac80211/src/include/linux/ieee80211.h
new file mode 100644 (file)
index 0000000..30621c2
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * IEEE 802.11 defines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define FCS_LEN 4
+
+#define IEEE80211_FCTL_VERS            0x0003
+#define IEEE80211_FCTL_FTYPE           0x000c
+#define IEEE80211_FCTL_STYPE           0x00f0
+#define IEEE80211_FCTL_TODS            0x0100
+#define IEEE80211_FCTL_FROMDS          0x0200
+#define IEEE80211_FCTL_MOREFRAGS       0x0400
+#define IEEE80211_FCTL_RETRY           0x0800
+#define IEEE80211_FCTL_PM              0x1000
+#define IEEE80211_FCTL_MOREDATA                0x2000
+#define IEEE80211_FCTL_PROTECTED       0x4000
+#define IEEE80211_FCTL_ORDER           0x8000
+
+#define IEEE80211_SCTL_FRAG            0x000F
+#define IEEE80211_SCTL_SEQ             0xFFF0
+
+#define IEEE80211_FTYPE_MGMT           0x0000
+#define IEEE80211_FTYPE_CTL            0x0004
+#define IEEE80211_FTYPE_DATA           0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ      0x0000
+#define IEEE80211_STYPE_ASSOC_RESP     0x0010
+#define IEEE80211_STYPE_REASSOC_REQ    0x0020
+#define IEEE80211_STYPE_REASSOC_RESP   0x0030
+#define IEEE80211_STYPE_PROBE_REQ      0x0040
+#define IEEE80211_STYPE_PROBE_RESP     0x0050
+#define IEEE80211_STYPE_BEACON         0x0080
+#define IEEE80211_STYPE_ATIM           0x0090
+#define IEEE80211_STYPE_DISASSOC       0x00A0
+#define IEEE80211_STYPE_AUTH           0x00B0
+#define IEEE80211_STYPE_DEAUTH         0x00C0
+#define IEEE80211_STYPE_ACTION         0x00D0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL         0x00A0
+#define IEEE80211_STYPE_RTS            0x00B0
+#define IEEE80211_STYPE_CTS            0x00C0
+#define IEEE80211_STYPE_ACK            0x00D0
+#define IEEE80211_STYPE_CFEND          0x00E0
+#define IEEE80211_STYPE_CFENDACK       0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA                   0x0000
+#define IEEE80211_STYPE_DATA_CFACK             0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL            0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL         0x0030
+#define IEEE80211_STYPE_NULLFUNC               0x0040
+#define IEEE80211_STYPE_CFACK                  0x0050
+#define IEEE80211_STYPE_CFPOLL                 0x0060
+#define IEEE80211_STYPE_CFACKPOLL              0x0070
+#define IEEE80211_STYPE_QOS_DATA               0x0080
+#define IEEE80211_STYPE_QOS_DATA_CFACK         0x0090
+#define IEEE80211_STYPE_QOS_DATA_CFPOLL                0x00A0
+#define IEEE80211_STYPE_QOS_DATA_CFACKPOLL     0x00B0
+#define IEEE80211_STYPE_QOS_NULLFUNC           0x00C0
+#define IEEE80211_STYPE_QOS_CFACK              0x00D0
+#define IEEE80211_STYPE_QOS_CFPOLL             0x00E0
+#define IEEE80211_STYPE_QOS_CFACKPOLL          0x00F0
+
+
+/* miscellaneous IEEE 802.11 constants */
+#define IEEE80211_MAX_FRAG_THRESHOLD   2346
+#define IEEE80211_MAX_RTS_THRESHOLD    2347
+#define IEEE80211_MAX_AID              2007
+#define IEEE80211_MAX_TIM_LEN          251
+#define IEEE80211_MAX_DATA_LEN         2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+#define IEEE80211_MAX_SSID_LEN         32
+
+struct ieee80211_hdr {
+       __le16 frame_control;
+       __le16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6];
+       u8 addr3[6];
+       __le16 seq_ctrl;
+       u8 addr4[6];
+} __attribute__ ((packed));
+
+
+struct ieee80211_mgmt {
+       __le16 frame_control;
+       __le16 duration;
+       u8 da[6];
+       u8 sa[6];
+       u8 bssid[6];
+       __le16 seq_ctrl;
+       union {
+               struct {
+                       __le16 auth_alg;
+                       __le16 auth_transaction;
+                       __le16 status_code;
+                       /* possibly followed by Challenge text */
+                       u8 variable[0];
+               } __attribute__ ((packed)) auth;
+               struct {
+                       __le16 reason_code;
+               } __attribute__ ((packed)) deauth;
+               struct {
+                       __le16 capab_info;
+                       __le16 listen_interval;
+                       /* followed by SSID and Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) assoc_req;
+               struct {
+                       __le16 capab_info;
+                       __le16 status_code;
+                       __le16 aid;
+                       /* followed by Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+               struct {
+                       __le16 capab_info;
+                       __le16 listen_interval;
+                       u8 current_ap[6];
+                       /* followed by SSID and Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) reassoc_req;
+               struct {
+                       __le16 reason_code;
+               } __attribute__ ((packed)) disassoc;
+               struct {
+                       __le64 timestamp;
+                       __le16 beacon_int;
+                       __le16 capab_info;
+                       /* followed by some of SSID, Supported rates,
+                        * FH Params, DS Params, CF Params, IBSS Params, TIM */
+                       u8 variable[0];
+               } __attribute__ ((packed)) beacon;
+               struct {
+                       /* only variable items: SSID, Supported rates */
+                       u8 variable[0];
+               } __attribute__ ((packed)) probe_req;
+               struct {
+                       __le64 timestamp;
+                       __le16 beacon_int;
+                       __le16 capab_info;
+                       /* followed by some of SSID, Supported rates,
+                        * FH Params, DS Params, CF Params, IBSS Params */
+                       u8 variable[0];
+               } __attribute__ ((packed)) probe_resp;
+               struct {
+                       u8 category;
+                       union {
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 status_code;
+                                       u8 variable[0];
+                               } __attribute__ ((packed)) wme_action;
+                               struct{
+                                       u8 action_code;
+                                       u8 element_id;
+                                       u8 length;
+                                       u8 switch_mode;
+                                       u8 new_chan;
+                                       u8 switch_count;
+                               } __attribute__((packed)) chan_switch;
+                       } u;
+               } __attribute__ ((packed)) action;
+       } u;
+} __attribute__ ((packed));
+
+
+/* Control frames */
+struct ieee80211_rts {
+       __le16 frame_control;
+       __le16 duration;
+       u8 ra[6];
+       u8 ta[6];
+} __attribute__ ((packed));
+
+struct ieee80211_cts {
+       __le16 frame_control;
+       __le16 duration;
+       u8 ra[6];
+} __attribute__ ((packed));
+
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+#define WLAN_AUTH_FAST_BSS_TRANSITION 2
+#define WLAN_AUTH_LEAP 128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS            (1<<0)
+#define WLAN_CAPABILITY_IBSS           (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE    (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST        (1<<3)
+#define WLAN_CAPABILITY_PRIVACY                (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC           (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY        (1<<7)
+/* 802.11h */
+#define WLAN_CAPABILITY_SPECTRUM_MGMT  (1<<8)
+#define WLAN_CAPABILITY_QOS            (1<<9)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME        (1<<10)
+#define WLAN_CAPABILITY_DSSS_OFDM      (1<<13)
+
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
+/* WLAN_ERP_BARKER_PREAMBLE values */
+enum {
+       WLAN_ERP_PREAMBLE_SHORT = 0,
+       WLAN_ERP_PREAMBLE_LONG = 1,
+};
+
+/* Status codes */
+enum ieee80211_statuscode {
+       WLAN_STATUS_SUCCESS = 0,
+       WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
+       WLAN_STATUS_CAPS_UNSUPPORTED = 10,
+       WLAN_STATUS_REASSOC_NO_ASSOC = 11,
+       WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
+       WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
+       WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
+       WLAN_STATUS_CHALLENGE_FAIL = 15,
+       WLAN_STATUS_AUTH_TIMEOUT = 16,
+       WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+       WLAN_STATUS_ASSOC_DENIED_RATES = 18,
+       /* 802.11b */
+       WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
+       WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
+       WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
+       /* 802.11h */
+       WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
+       WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
+       WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
+       /* 802.11g */
+       WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
+       WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+       /* 802.11i */
+       WLAN_STATUS_INVALID_IE = 40,
+       WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
+       WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
+       WLAN_STATUS_INVALID_AKMP = 43,
+       WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
+       WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
+       WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+};
+
+
+/* Reason codes */
+enum ieee80211_reasoncode {
+       WLAN_REASON_UNSPECIFIED = 1,
+       WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+       WLAN_REASON_DEAUTH_LEAVING = 3,
+       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
+       WLAN_REASON_DISASSOC_AP_BUSY = 5,
+       WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+       WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+       WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
+       WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+       /* 802.11h */
+       WLAN_REASON_DISASSOC_BAD_POWER = 10,
+       WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
+       /* 802.11i */
+       WLAN_REASON_INVALID_IE = 13,
+       WLAN_REASON_MIC_FAILURE = 14,
+       WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+       WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
+       WLAN_REASON_IE_DIFFERENT = 17,
+       WLAN_REASON_INVALID_GROUP_CIPHER = 18,
+       WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
+       WLAN_REASON_INVALID_AKMP = 20,
+       WLAN_REASON_UNSUPP_RSN_VERSION = 21,
+       WLAN_REASON_INVALID_RSN_IE_CAP = 22,
+       WLAN_REASON_IEEE8021X_FAILED = 23,
+       WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+};
+
+
+/* Information Element IDs */
+enum ieee80211_eid {
+       WLAN_EID_SSID = 0,
+       WLAN_EID_SUPP_RATES = 1,
+       WLAN_EID_FH_PARAMS = 2,
+       WLAN_EID_DS_PARAMS = 3,
+       WLAN_EID_CF_PARAMS = 4,
+       WLAN_EID_TIM = 5,
+       WLAN_EID_IBSS_PARAMS = 6,
+       WLAN_EID_CHALLENGE = 16,
+       /* 802.11d */
+       WLAN_EID_COUNTRY = 7,
+       WLAN_EID_HP_PARAMS = 8,
+       WLAN_EID_HP_TABLE = 9,
+       WLAN_EID_REQUEST = 10,
+       /* 802.11h */
+       WLAN_EID_PWR_CONSTRAINT = 32,
+       WLAN_EID_PWR_CAPABILITY = 33,
+       WLAN_EID_TPC_REQUEST = 34,
+       WLAN_EID_TPC_REPORT = 35,
+       WLAN_EID_SUPPORTED_CHANNELS = 36,
+       WLAN_EID_CHANNEL_SWITCH = 37,
+       WLAN_EID_MEASURE_REQUEST = 38,
+       WLAN_EID_MEASURE_REPORT = 39,
+       WLAN_EID_QUIET = 40,
+       WLAN_EID_IBSS_DFS = 41,
+       /* 802.11g */
+       WLAN_EID_ERP_INFO = 42,
+       WLAN_EID_EXT_SUPP_RATES = 50,
+       /* 802.11i */
+       WLAN_EID_RSN = 48,
+       WLAN_EID_WPA = 221,
+       WLAN_EID_GENERIC = 221,
+       WLAN_EID_VENDOR_SPECIFIC = 221,
+       WLAN_EID_QOS_PARAMETER = 222
+};
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP    0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40                0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP         0x000FAC02
+/* reserved:                           0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP         0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
+
+#define WLAN_MAX_KEY_LEN               32
+
+/**
+ * ieee80211_get_SA - get pointer to SA
+ *
+ * Given an 802.11 frame, this function returns the offset
+ * to the source address (SA). It does not verify that the
+ * header is long enough to contain the address, and the
+ * header must be long enough to contain the frame control
+ * field.
+ *
+ * @hdr: the frame
+ */
+static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
+{
+       u8 *raw = (u8 *) hdr;
+       u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */
+
+       switch (tofrom) {
+               case 2:
+                       return hdr->addr3;
+               case 3:
+                       return hdr->addr4;
+       }
+       return hdr->addr2;
+}
+
+/**
+ * ieee80211_get_DA - get pointer to DA
+ *
+ * Given an 802.11 frame, this function returns the offset
+ * to the destination address (DA). It does not verify that
+ * the header is long enough to contain the address, and the
+ * header must be long enough to contain the frame control
+ * field.
+ *
+ * @hdr: the frame
+ */
+static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
+{
+       u8 *raw = (u8 *) hdr;
+       u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */
+
+       if (to_ds)
+               return hdr->addr3;
+       return hdr->addr1;
+}
+
+/**
+ * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set
+ *
+ * This function determines whether the "more fragments" bit is set
+ * in the frame.
+ *
+ * @hdr: the frame
+ */
+static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
+{
+       return (le16_to_cpu(hdr->frame_control) &
+               IEEE80211_FCTL_MOREFRAGS) != 0;
+}
+
+#endif /* IEEE80211_H */
diff --git a/package/mac80211/src/include/linux/nl80211.h b/package/mac80211/src/include/linux/nl80211.h
new file mode 100644 (file)
index 0000000..a5dd030
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ *     to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and
+ *     %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ *     or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ *     %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ *     %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ *     either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ *     on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+       %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ *     to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ *     %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ *     be sent from userspace to request creation of a new virtual interface,
+ *     then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ *     %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ *     userspace to request deletion of a virtual interface, then requires
+ *     attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+       NL80211_CMD_UNSPEC,
+
+       NL80211_CMD_GET_WIPHY,          /* can dump */
+       NL80211_CMD_SET_WIPHY,
+       NL80211_CMD_NEW_WIPHY,
+       NL80211_CMD_DEL_WIPHY,
+
+       NL80211_CMD_GET_INTERFACE,      /* can dump */
+       NL80211_CMD_SET_INTERFACE,
+       NL80211_CMD_NEW_INTERFACE,
+       NL80211_CMD_DEL_INTERFACE,
+
+       /* add commands here */
+
+       /* used to define NL80211_CMD_MAX below */
+       __NL80211_CMD_AFTER_LAST,
+       NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ *     /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything inbetween, this is ABI! */
+       NL80211_ATTR_UNSPEC,
+
+       NL80211_ATTR_WIPHY,
+       NL80211_ATTR_WIPHY_NAME,
+
+       NL80211_ATTR_IFINDEX,
+       NL80211_ATTR_IFNAME,
+       NL80211_ATTR_IFTYPE,
+
+       /* add attributes here, update the policy in nl80211.c */
+
+       __NL80211_ATTR_AFTER_LAST,
+       NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+       NL80211_IFTYPE_UNSPECIFIED,
+       NL80211_IFTYPE_ADHOC,
+       NL80211_IFTYPE_STATION,
+       NL80211_IFTYPE_AP,
+       NL80211_IFTYPE_AP_VLAN,
+       NL80211_IFTYPE_WDS,
+       NL80211_IFTYPE_MONITOR,
+
+       /* keep last */
+       __NL80211_IFTYPE_AFTER_LAST,
+       NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/package/mac80211/src/include/net/cfg80211.h b/package/mac80211/src/include/net/cfg80211.h
new file mode 100644 (file)
index 0000000..d30960e
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __NET_CFG80211_H
+#define __NET_CFG80211_H
+
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/nl80211.h>
+#include <net/genetlink.h>
+
+/*
+ * 802.11 configuration in-kernel interface
+ *
+ * Copyright 2006, 2007        Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/* Radiotap header iteration
+ *   implemented in net/wireless/radiotap.c
+ *   docs in Documentation/networking/radiotap-headers.txt
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+       struct ieee80211_radiotap_header *rtheader;
+       int max_length;
+       int this_arg_index;
+       u8 *this_arg;
+
+       int arg_index;
+       u8 *arg;
+       __le32 *next_bitmap;
+       u32 bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+   struct ieee80211_radiotap_iterator *iterator,
+   struct ieee80211_radiotap_header *radiotap_header,
+   int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+   struct ieee80211_radiotap_iterator *iterator);
+
+
+/* from net/wireless.h */
+struct wiphy;
+
+/**
+ * struct cfg80211_ops - backend description for wireless configuration
+ *
+ * This struct is registered by fullmac card drivers and/or wireless stacks
+ * in order to handle configuration requests on their interfaces.
+ *
+ * All callbacks except where otherwise noted should return 0
+ * on success or a negative error code.
+ *
+ * All operations are currently invoked under rtnl for consistency with the
+ * wireless extensions but this is subject to reevaluation as soon as this
+ * code is used more widely and we have a first user without wext.
+ *
+ * @add_virtual_intf: create a new virtual interface with the given name
+ *
+ * @del_virtual_intf: remove the virtual interface determined by ifindex.
+ *
+ * @change_virtual_intf: change type of virtual interface
+ *
+ */
+struct cfg80211_ops {
+       int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
+                                   enum nl80211_iftype type);
+       int     (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
+       int     (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
+                                      enum nl80211_iftype type);
+};
+
+#endif /* __NET_CFG80211_H */
diff --git a/package/mac80211/src/include/net/ieee80211_radiotap.h b/package/mac80211/src/include/net/ieee80211_radiotap.h
new file mode 100644 (file)
index 0000000..dfd8bf6
--- /dev/null
@@ -0,0 +1,268 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+
+/* Radiotap header version (from official NetBSD feed) */
+#define IEEE80211RADIOTAP_VERSION      "1.5"
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION                0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* XXX tcpdump/libpcap do not tolerate variable-length headers,
+ * yet, so we pad every radiotap header to 64 bytes. Ugh.
+ */
+#define IEEE80211_RADIOTAP_HDRLEN      64
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+       u8 it_version;          /* Version 0. Only increases
+                                * for drastic changes,
+                                * introduction of compatible
+                                * new fields does not count.
+                                */
+       u8 it_pad;
+       __le16 it_len;          /* length of the whole
+                                * header in bytes, including
+                                * it_version, it_pad,
+                                * it_len, and data fields.
+                                */
+       __le32 it_present;      /* A bitmap telling which
+                                * fields are present. Set bit 31
+                                * (0x80000000) to extend the
+                                * bitmap by another 32 bits.
+                                * Additional extensions are made
+                                * by setting bit 31.
+                                */
+};
+
+/* Name                                 Data type    Units
+ * ----                                 ---------    -----
+ *
+ * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
+ *
+ *      Value in microseconds of the MAC's 64-bit 802.11 Time
+ *      Synchronization Function timer when the first bit of the
+ *      MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL           2 x __le16   MHz, bitmap
+ *
+ *      Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS              __le16       see below
+ *
+ *      For frequency-hopping radios, the hop set (first byte)
+ *      and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE              u8           500kb/s
+ *
+ *      Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      RF signal power at the antenna, decibel difference from
+ *      one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      RF noise power at the antenna, decibel difference from one
+ *      milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
+ *
+ *      RF signal power at the antenna, decibel difference from an
+ *      arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
+ *
+ *      RF noise power at the antenna, decibel difference from an
+ *      arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY      __le16       unitless
+ *
+ *      Quality of Barker code lock. Unitless. Monotonically
+ *      nondecreasing with "better" lock strength. Called "Signal
+ *      Quality" in datasheets.  (Is there a standard way to measure
+ *      this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION    __le16       unitless
+ *
+ *      Transmit power expressed as unitless distance from max
+ *      power set at factory calibration.  0 is max power.
+ *      Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16       decibels (dB)
+ *
+ *      Transmit power expressed as decibel distance from max power
+ *      set at factory calibration.  0 is max power.  Monotonically
+ *      nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      Transmit power expressed as dBm (decibels from a 1 milliwatt
+ *      reference). This is the absolute power level measured at
+ *      the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
+ *
+ *      Properties of transmitted and received frames. See flags
+ *      defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
+ *
+ *      Unitless indication of the Rx/Tx antenna for this packet.
+ *      The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS          __le16       bitmap
+ *
+ *     Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS          __le16       bitmap
+ *
+ *     Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
+ *
+ *     Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
+ *
+ *     Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+       IEEE80211_RADIOTAP_TSFT = 0,
+       IEEE80211_RADIOTAP_FLAGS = 1,
+       IEEE80211_RADIOTAP_RATE = 2,
+       IEEE80211_RADIOTAP_CHANNEL = 3,
+       IEEE80211_RADIOTAP_FHSS = 4,
+       IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+       IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+       IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+       IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+       IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+       IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+       IEEE80211_RADIOTAP_ANTENNA = 11,
+       IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+       IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+       IEEE80211_RADIOTAP_RX_FLAGS = 14,
+       IEEE80211_RADIOTAP_TX_FLAGS = 15,
+       IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+       IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+       IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define        IEEE80211_CHAN_TURBO    0x0010  /* Turbo channel */
+#define        IEEE80211_CHAN_CCK      0x0020  /* CCK channel */
+#define        IEEE80211_CHAN_OFDM     0x0040  /* OFDM channel */
+#define        IEEE80211_CHAN_2GHZ     0x0080  /* 2 GHz spectrum channel. */
+#define        IEEE80211_CHAN_5GHZ     0x0100  /* 5 GHz spectrum channel */
+#define        IEEE80211_CHAN_PASSIVE  0x0200  /* Only passive scan allowed */
+#define        IEEE80211_CHAN_DYN      0x0400  /* Dynamic CCK-OFDM channel */
+#define        IEEE80211_CHAN_GFSK     0x0800  /* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define        IEEE80211_RADIOTAP_F_CFP        0x01    /* sent/received
+                                                * during CFP
+                                                */
+#define        IEEE80211_RADIOTAP_F_SHORTPRE   0x02    /* sent/received
+                                                * with short
+                                                * preamble
+                                                */
+#define        IEEE80211_RADIOTAP_F_WEP        0x04    /* sent/received
+                                                * with WEP encryption
+                                                */
+#define        IEEE80211_RADIOTAP_F_FRAG       0x08    /* sent/received
+                                                * with fragmentation
+                                                */
+#define        IEEE80211_RADIOTAP_F_FCS        0x10    /* frame includes FCS */
+#define        IEEE80211_RADIOTAP_F_DATAPAD    0x20    /* frame has padding between
+                                                * 802.11 header and payload
+                                                * (to 32-bit boundary)
+                                                */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001  /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL   0x0001  /* failed due to excessive
+                                                * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS    0x0002  /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS    0x0004  /* used rts/cts handshake */
+
+/* Ugly macro to convert literal channel numbers into their mhz equivalents
+ * There are certianly some conditions that will break this (like feeding it '30')
+ * but they shouldn't arise since nothing talks on channel 30. */
+#define ieee80211chan2mhz(x) \
+       (((x) <= 14) ? \
+       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
+       ((x) + 1000) * 5)
+
+/* helpers */
+static inline int ieee80211_get_radiotap_len(unsigned char *data)
+{
+       struct ieee80211_radiotap_header *hdr =
+               (struct ieee80211_radiotap_header *)data;
+
+       return le16_to_cpu(get_unaligned(&hdr->it_len));
+}
+
+#endif                         /* IEEE80211_RADIOTAP_H */
diff --git a/package/mac80211/src/include/net/mac80211.h b/package/mac80211/src/include/net/mac80211.h
new file mode 100644 (file)
index 0000000..2b1bffb
--- /dev/null
@@ -0,0 +1,1429 @@
+/*
+ * mac80211 <-> driver interface
+ *
+ * Copyright 2002-2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MAC80211_H
+#define MAC80211_H
+
+#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <linux/device.h>
+#include <linux/ieee80211.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+
+/**
+ * DOC: Introduction
+ *
+ * mac80211 is the Linux stack for 802.11 hardware that implements
+ * only partial functionality in hard- or firmware. This document
+ * defines the interface between mac80211 and low-level hardware
+ * drivers.
+ */
+
+/**
+ * DOC: Calling mac80211 from interrupts
+ *
+ * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be
+ * called in hardware interrupt context. The low-level driver must not call any
+ * other functions in hardware interrupt context. If there is a need for such
+ * call, the low-level driver should first ACK the interrupt and perform the
+ * IEEE 802.11 code call after this, e.g. from a scheduled workqueue function.
+ */
+
+/**
+ * DOC: Warning
+ *
+ * If you're reading this document and not the header file itself, it will
+ * be incomplete because not all documentation has been converted yet.
+ */
+
+/**
+ * DOC: Frame format
+ *
+ * As a general rule, when frames are passed between mac80211 and the driver,
+ * they start with the IEEE 802.11 header and include the same octets that are
+ * sent over the air except for the FCS which should be calculated by the
+ * hardware.
+ *
+ * There are, however, various exceptions to this rule for advanced features:
+ *
+ * The first exception is for hardware encryption and decryption offload
+ * where the IV/ICV may or may not be generated in hardware.
+ *
+ * Secondly, when the hardware handles fragmentation, the frame handed to
+ * the driver from mac80211 is the MSDU, not the MPDU.
+ *
+ * Finally, for received frames, the driver is able to indicate that it has
+ * filled a radiotap header and put that in front of the frame; if it does
+ * not do so then mac80211 may add this under certain circumstances.
+ */
+
+#define IEEE80211_CHAN_W_SCAN 0x00000001
+#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002
+#define IEEE80211_CHAN_W_IBSS 0x00000004
+
+/* Channel information structure. Low-level driver is expected to fill in chan,
+ * freq, and val fields. Other fields will be filled in by 80211.o based on
+ * hostapd information and low-level driver does not need to use them. The
+ * limits for each channel will be provided in 'struct ieee80211_conf' when
+ * configuring the low-level driver with hw->config callback. If a device has
+ * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED
+ * can be set to let the driver configure all fields */
+struct ieee80211_channel {
+       short chan; /* channel number (IEEE 802.11) */
+       short freq; /* frequency in MHz */
+       int val; /* hw specific value for the channel */
+       int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+       unsigned char power_level;
+       unsigned char antenna_max;
+};
+
+#define IEEE80211_RATE_ERP 0x00000001
+#define IEEE80211_RATE_BASIC 0x00000002
+#define IEEE80211_RATE_PREAMBLE2 0x00000004
+#define IEEE80211_RATE_SUPPORTED 0x00000010
+#define IEEE80211_RATE_OFDM 0x00000020
+#define IEEE80211_RATE_CCK 0x00000040
+#define IEEE80211_RATE_MANDATORY 0x00000100
+
+#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2)
+#define IEEE80211_RATE_MODULATION(f) \
+       (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM))
+
+/* Low-level driver should set PREAMBLE2, OFDM and CCK flags.
+ * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the
+ * configuration. */
+struct ieee80211_rate {
+       int rate; /* rate in 100 kbps */
+       int val; /* hw specific value for the rate */
+       int flags; /* IEEE80211_RATE_ flags */
+       int val2; /* hw specific value for the rate when using short preamble
+                  * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for
+                  * 2, 5.5, and 11 Mbps) */
+       signed char min_rssi_ack;
+       unsigned char min_rssi_ack_delta;
+
+       /* following fields are set by 80211.o and need not be filled by the
+        * low-level driver */
+       int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for
+                      * optimizing channel utilization estimates */
+};
+
+/**
+ * enum ieee80211_phymode - PHY modes
+ *
+ * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h
+ * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b
+ * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM),
+ *     backwards compatible with 11b mode
+ * @NUM_IEEE80211_MODES: internal
+ */
+enum ieee80211_phymode {
+       MODE_IEEE80211A,
+       MODE_IEEE80211B,
+       MODE_IEEE80211G,
+
+       /* keep last */
+       NUM_IEEE80211_MODES
+};
+
+/**
+ * struct ieee80211_hw_mode - PHY mode definition
+ *
+ * This structure describes the capabilities supported by the device
+ * in a single PHY mode.
+ *
+ * @mode: the PHY mode for this definition
+ * @num_channels: number of supported channels
+ * @channels: pointer to array of supported channels
+ * @num_rates: number of supported bitrates
+ * @rates: pointer to array of supported bitrates
+ * @list: internal
+ */
+struct ieee80211_hw_mode {
+       struct list_head list;
+       struct ieee80211_channel *channels;
+       struct ieee80211_rate *rates;
+       enum ieee80211_phymode mode;
+       int num_channels;
+       int num_rates;
+};
+
+/**
+ * struct ieee80211_tx_queue_params - transmit queue configuration
+ *
+ * The information provided in this structure is required for QoS
+ * transmit queue configuration.
+ *
+ * @aifs: arbitration interface space [0..255, -1: use default]
+ * @cw_min: minimum contention window [will be a value of the form
+ *     2^n-1 in the range 1..1023; 0: use default]
+ * @cw_max: maximum contention window [like @cw_min]
+ * @burst_time: maximum burst time in units of 0.1ms, 0 meaning disabled
+ */
+struct ieee80211_tx_queue_params {
+       int aifs;
+       int cw_min;
+       int cw_max;
+       int burst_time;
+};
+
+/**
+ * struct ieee80211_tx_queue_stats_data - transmit queue statistics
+ *
+ * @len: number of packets in queue
+ * @limit: queue length limit
+ * @count: number of frames sent
+ */
+struct ieee80211_tx_queue_stats_data {
+       unsigned int len;
+       unsigned int limit;
+       unsigned int count;
+};
+
+/**
+ * enum ieee80211_tx_queue - transmit queue number
+ *
+ * These constants are used with some callbacks that take a
+ * queue number to set parameters for a queue.
+ *
+ * @IEEE80211_TX_QUEUE_DATA0: data queue 0
+ * @IEEE80211_TX_QUEUE_DATA1: data queue 1
+ * @IEEE80211_TX_QUEUE_DATA2: data queue 2
+ * @IEEE80211_TX_QUEUE_DATA3: data queue 3
+ * @IEEE80211_TX_QUEUE_DATA4: data queue 4
+ * @IEEE80211_TX_QUEUE_SVP: ??
+ * @NUM_TX_DATA_QUEUES: number of data queues
+ * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
+ *     sent after a beacon
+ * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
+ */
+enum ieee80211_tx_queue {
+       IEEE80211_TX_QUEUE_DATA0,
+       IEEE80211_TX_QUEUE_DATA1,
+       IEEE80211_TX_QUEUE_DATA2,
+       IEEE80211_TX_QUEUE_DATA3,
+       IEEE80211_TX_QUEUE_DATA4,
+       IEEE80211_TX_QUEUE_SVP,
+
+       NUM_TX_DATA_QUEUES,
+
+/* due to stupidity in the sub-ioctl userspace interface, the items in
+ * this struct need to have fixed values. As soon as it is removed, we can
+ * fix these entries. */
+       IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+       IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+struct ieee80211_tx_queue_stats {
+       struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+};
+
+struct ieee80211_low_level_stats {
+       unsigned int dot11ACKFailureCount;
+       unsigned int dot11RTSFailureCount;
+       unsigned int dot11FCSErrorCount;
+       unsigned int dot11RTSSuccessCount;
+};
+
+/* Transmit control fields. This data structure is passed to low-level driver
+ * with each TX frame. The low-level driver is responsible for configuring
+ * the hardware to use given values (depending on what is supported). */
+
+struct ieee80211_tx_control {
+       int tx_rate; /* Transmit rate, given as the hw specific value for the
+                     * rate (from struct ieee80211_rate) */
+       int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
+                          * specific value for the rate (from
+                          * struct ieee80211_rate) */
+
+#define IEEE80211_TXCTL_REQ_TX_STATUS  (1<<0)/* request TX status callback for
+                                               * this frame */
+#define IEEE80211_TXCTL_DO_NOT_ENCRYPT (1<<1) /* send this frame without
+                                               * encryption; e.g., for EAPOL
+                                               * frames */
+#define IEEE80211_TXCTL_USE_RTS_CTS    (1<<2) /* use RTS-CTS before sending
+                                               * frame */
+#define IEEE80211_TXCTL_USE_CTS_PROTECT        (1<<3) /* use CTS protection for the
+                                               * frame (e.g., for combined
+                                               * 802.11g / 802.11b networks) */
+#define IEEE80211_TXCTL_NO_ACK         (1<<4) /* tell the low level not to
+                                               * wait for an ack */
+#define IEEE80211_TXCTL_RATE_CTRL_PROBE        (1<<5)
+#define IEEE80211_TXCTL_CLEAR_DST_MASK (1<<6)
+#define IEEE80211_TXCTL_REQUEUE                (1<<7)
+#define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of
+                                               * the frame */
+#define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send
+                                                 * using the through
+                                                 * set_retry_limit configured
+                                                 * long retry value */
+       u32 flags;                             /* tx control flags defined
+                                               * above */
+       u8 key_idx;             /* keyidx from hw->set_key(), undefined if
+                                * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */
+       u8 retry_limit;         /* 1 = only first attempt, 2 = one retry, ..
+                                * This could be used when set_retry_limit
+                                * is not implemented by the driver */
+       u8 power_level;         /* per-packet transmit power level, in dBm */
+       u8 antenna_sel_tx;      /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+       u8 icv_len;             /* length of the ICV/MIC field in octets */
+       u8 iv_len;              /* length of the IV field in octets */
+       u8 queue;               /* hardware queue to use for this frame;
+                                * 0 = highest, hw->queues-1 = lowest */
+       struct ieee80211_rate *rate;            /* internal 80211.o rate */
+       struct ieee80211_rate *rts_rate;        /* internal 80211.o rate
+                                                * for RTS/CTS */
+       int alt_retry_rate; /* retry rate for the last retries, given as the
+                            * hw specific value for the rate (from
+                            * struct ieee80211_rate). To be used to limit
+                            * packet dropping when probing higher rates, if hw
+                            * supports multiple retry rates. -1 = not used */
+       int type;       /* internal */
+       int ifindex;    /* internal */
+};
+
+
+/**
+ * enum mac80211_rx_flags - receive flags
+ *
+ * These flags are used with the @flag member of &struct ieee80211_rx_status.
+ * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame.
+ *     Use together with %RX_FLAG_MMIC_STRIPPED.
+ * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware.
+ * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header.
+ * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame,
+ *     verification has been done by the hardware.
+ * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame.
+ *     If this flag is set, the stack cannot do any replay detection
+ *     hence the driver or hardware will have to do that.
+ * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on
+ *     the frame.
+ * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
+ *     the frame.
+ */
+enum mac80211_rx_flags {
+       RX_FLAG_MMIC_ERROR      = 1<<0,
+       RX_FLAG_DECRYPTED       = 1<<1,
+       RX_FLAG_RADIOTAP        = 1<<2,
+       RX_FLAG_MMIC_STRIPPED   = 1<<3,
+       RX_FLAG_IV_STRIPPED     = 1<<4,
+       RX_FLAG_FAILED_FCS_CRC  = 1<<5,
+       RX_FLAG_FAILED_PLCP_CRC = 1<<6,
+};
+
+/**
+ * struct ieee80211_rx_status - receive status
+ *
+ * The low-level driver should provide this information (the subset
+ * supported by hardware) to the 802.11 code with each received
+ * frame.
+ * @mactime: MAC timestamp as defined by 802.11
+ * @freq: frequency the radio was tuned to when receiving this frame, in MHz
+ * @channel: channel the radio was tuned to
+ * @phymode: active PHY mode
+ * @ssi: signal strength when receiving this frame
+ * @signal: used as 'qual' in statistics reporting
+ * @noise: PHY noise when receiving this frame
+ * @antenna: antenna used
+ * @rate: data rate
+ * @flag: %RX_FLAG_*
+ */
+struct ieee80211_rx_status {
+       u64 mactime;
+       int freq;
+       int channel;
+       enum ieee80211_phymode phymode;
+       int ssi;
+       int signal;
+       int noise;
+       int antenna;
+       int rate;
+       int flag;
+};
+
+/**
+ * enum ieee80211_tx_status_flags - transmit status flags
+ *
+ * Status flags to indicate various transmit conditions.
+ *
+ * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
+ *     because the destination STA was in powersave mode.
+ *
+ * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
+ */
+enum ieee80211_tx_status_flags {
+       IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
+       IEEE80211_TX_STATUS_ACK         = 1<<1,
+};
+
+/**
+ * struct ieee80211_tx_status - transmit status
+ *
+ * As much information as possible should be provided for each transmitted
+ * frame with ieee80211_tx_status().
+ *
+ * @control: a copy of the &struct ieee80211_tx_control passed to the driver
+ *     in the tx() callback.
+ *
+ * @flags: transmit status flags, defined above
+ *
+ * @ack_signal: signal strength of the ACK frame
+ *
+ * @excessive_retries: set to 1 if the frame was retried many times
+ *     but not acknowledged
+ *
+ * @retry_count: number of retries
+ *
+ * @queue_length: ?? REMOVE
+ * @queue_number: ?? REMOVE
+ */
+struct ieee80211_tx_status {
+       struct ieee80211_tx_control control;
+       u8 flags;
+       bool excessive_retries;
+       u8 retry_count;
+       int ack_signal;
+       int queue_length;
+       int queue_number;
+};
+
+/**
+ * enum ieee80211_conf_flags - configuration flags
+ *
+ * Flags to define PHY configuration options
+ *
+ * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
+ * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
+ *
+ */
+enum ieee80211_conf_flags {
+       IEEE80211_CONF_SHORT_SLOT_TIME  = 1<<0,
+       IEEE80211_CONF_RADIOTAP         = 1<<1,
+};
+
+/**
+ * struct ieee80211_conf - configuration of the device
+ *
+ * This struct indicates how the driver shall configure the hardware.
+ *
+ * @radio_enabled: when zero, driver is required to switch off the radio.
+ *     TODO make a flag
+ * @channel: IEEE 802.11 channel number
+ * @freq: frequency in MHz
+ * @channel_val: hardware specific channel value for the channel
+ * @phymode: PHY mode to activate (REMOVE)
+ * @chan: channel to switch to, pointer to the channel information
+ * @mode: pointer to mode definition
+ * @regulatory_domain: ??
+ * @beacon_int: beacon interval (TODO make interface config)
+ * @flags: configuration flags defined above
+ * @power_level: transmit power limit for current regulatory domain in dBm
+ * @antenna_max: maximum antenna gain
+ * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
+ *     1/2: antenna 0/1
+ * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+ */
+struct ieee80211_conf {
+       int channel;                    /* IEEE 802.11 channel number */
+       int freq;                       /* MHz */
+       int channel_val;                /* hw specific value for the channel */
+
+       enum ieee80211_phymode phymode;
+       struct ieee80211_channel *chan;
+       struct ieee80211_hw_mode *mode;
+       unsigned int regulatory_domain;
+       int radio_enabled;
+
+       int beacon_int;
+       u32 flags;
+       u8 power_level;
+       u8 antenna_max;
+       u8 antenna_sel_tx;
+       u8 antenna_sel_rx;
+};
+
+/**
+ * enum ieee80211_if_types - types of 802.11 network interfaces
+ *
+ * @IEEE80211_IF_TYPE_INVALID: invalid interface type, not used
+ *     by mac80211 itself
+ * @IEEE80211_IF_TYPE_AP: interface in AP mode.
+ * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap
+ *     daemon. Drivers should never see this type.
+ * @IEEE80211_IF_TYPE_STA: interface in STA (client) mode.
+ * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
+ * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
+ * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
+ * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
+ *     will never see this type.
+ */
+enum ieee80211_if_types {
+       IEEE80211_IF_TYPE_INVALID,
+       IEEE80211_IF_TYPE_AP,
+       IEEE80211_IF_TYPE_STA,
+       IEEE80211_IF_TYPE_IBSS,
+       IEEE80211_IF_TYPE_MNTR,
+       IEEE80211_IF_TYPE_WDS,
+       IEEE80211_IF_TYPE_VLAN,
+};
+
+/**
+ * struct ieee80211_if_init_conf - initial configuration of an interface
+ *
+ * @if_id: internal interface ID. This number has no particular meaning to
+ *     drivers and the only allowed usage is to pass it to
+ *     ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
+ *     This field is not valid for monitor interfaces
+ *     (interfaces of %IEEE80211_IF_TYPE_MNTR type).
+ * @type: one of &enum ieee80211_if_types constants. Determines the type of
+ *     added/removed interface.
+ * @mac_addr: pointer to MAC address of the interface. This pointer is valid
+ *     until the interface is removed (i.e. it cannot be used after
+ *     remove_interface() callback was called for this interface).
+ *
+ * This structure is used in add_interface() and remove_interface()
+ * callbacks of &struct ieee80211_hw.
+ *
+ * When you allow multiple interfaces to be added to your PHY, take care
+ * that the hardware can actually handle multiple MAC addresses. However,
+ * also take care that when there's no interface left with mac_addr != %NULL
+ * you remove the MAC address from the device to avoid acknowledging packets
+ * in pure monitor mode.
+ */
+struct ieee80211_if_init_conf {
+       int if_id;
+       enum ieee80211_if_types type;
+       void *mac_addr;
+};
+
+/**
+ * struct ieee80211_if_conf - configuration of an interface
+ *
+ * @type: type of the interface. This is always the same as was specified in
+ *     &struct ieee80211_if_init_conf. The type of an interface never changes
+ *     during the life of the interface; this field is present only for
+ *     convenience.
+ * @bssid: BSSID of the network we are associated to/creating.
+ * @ssid: used (together with @ssid_len) by drivers for hardware that
+ *     generate beacons independently. The pointer is valid only during the
+ *     config_interface() call, so copy the value somewhere if you need
+ *     it.
+ * @ssid_len: length of the @ssid field.
+ * @beacon: beacon template. Valid only if @host_gen_beacon_template in
+ *     &struct ieee80211_hw is set. The driver is responsible of freeing
+ *     the sk_buff.
+ * @beacon_control: tx_control for the beacon template, this field is only
+ *     valid when the @beacon field was set.
+ *
+ * This structure is passed to the config_interface() callback of
+ * &struct ieee80211_hw.
+ */
+struct ieee80211_if_conf {
+       int type;
+       u8 *bssid;
+       u8 *ssid;
+       size_t ssid_len;
+       struct sk_buff *beacon;
+       struct ieee80211_tx_control *beacon_control;
+};
+
+/**
+ * enum ieee80211_key_alg - key algorithm
+ * @ALG_WEP: WEP40 or WEP104
+ * @ALG_TKIP: TKIP
+ * @ALG_CCMP: CCMP (AES)
+ */
+enum ieee80211_key_alg {
+       ALG_WEP,
+       ALG_TKIP,
+       ALG_CCMP,
+};
+
+
+/**
+ * enum ieee80211_key_flags - key flags
+ *
+ * These flags are used for communication about keys between the driver
+ * and mac80211, with the @flags parameter of &struct ieee80211_key_conf.
+ *
+ * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates
+ *     that the STA this key will be used with could be using QoS.
+ * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
+ *     driver to indicate that it requires IV generation for this
+ *     particular key.
+ * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
+ *     the driver for a TKIP key if it requires Michael MIC
+ *     generation in software.
+ */
+enum ieee80211_key_flags {
+       IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
+       IEEE80211_KEY_FLAG_GENERATE_IV  = 1<<1,
+       IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
+};
+
+/**
+ * struct ieee80211_key_conf - key information
+ *
+ * This key information is given by mac80211 to the driver by
+ * the set_key() callback in &struct ieee80211_ops.
+ *
+ * @hw_key_idx: To be set by the driver, this is the key index the driver
+ *     wants to be given when a frame is transmitted and needs to be
+ *     encrypted in hardware.
+ * @alg: The key algorithm.
+ * @flags: key flags, see &enum ieee80211_key_flags.
+ * @keyidx: the key index (0-3)
+ * @keylen: key material length
+ * @key: key material
+ */
+struct ieee80211_key_conf {
+       enum ieee80211_key_alg alg;
+       u8 hw_key_idx;
+       u8 flags;
+       s8 keyidx;
+       u8 keylen;
+       u8 key[0];
+};
+
+#define IEEE80211_SEQ_COUNTER_RX       0
+#define IEEE80211_SEQ_COUNTER_TX       1
+
+/**
+ * enum set_key_cmd - key command
+ *
+ * Used with the set_key() callback in &struct ieee80211_ops, this
+ * indicates whether a key is being removed or added.
+ *
+ * @SET_KEY: a key is set
+ * @DISABLE_KEY: a key must be disabled
+ */
+enum set_key_cmd {
+       SET_KEY, DISABLE_KEY,
+};
+
+/**
+ * enum sta_notify_cmd - sta notify command
+ *
+ * Used with the sta_notify() callback in &struct ieee80211_ops, this
+ * indicates addition and removal of a station to station table
+ *
+ * @STA_NOTIFY_ADD: a station was added to the station table
+ * @STA_NOTIFY_REMOVE: a station being removed from the station table
+ */
+enum sta_notify_cmd {
+       STA_NOTIFY_ADD, STA_NOTIFY_REMOVE
+};
+
+/**
+ * enum ieee80211_hw_flags - hardware flags
+ *
+ * These flags are used to indicate hardware capabilities to
+ * the stack. Generally, flags here should have their meaning
+ * done in a way that the simplest hardware doesn't need setting
+ * any particular flags. There are some exceptions to this rule,
+ * however, so you are advised to review these flags carefully.
+ *
+ * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE:
+ *     The device only needs to be supplied with a beacon template.
+ *     If you need the host to generate each beacon then don't use
+ *     this flag and call ieee80211_beacon_get() when you need the
+ *     next beacon frame. Note that if you set this flag, you must
+ *     implement the set_tim() callback for powersave mode to work
+ *     properly.
+ *     This flag is only relevant for access-point mode.
+ *
+ * @IEEE80211_HW_RX_INCLUDES_FCS:
+ *     Indicates that received frames passed to the stack include
+ *     the FCS at the end.
+ *
+ * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING:
+ *     Some wireless LAN chipsets buffer broadcast/multicast frames
+ *     for power saving stations in the hardware/firmware and others
+ *     rely on the host system for such buffering. This option is used
+ *     to configure the IEEE 802.11 upper layer to buffer broadcast and
+ *     multicast frames when there are power saving stations so that
+ *     the driver can fetch them with ieee80211_get_buffered_bc(). Note
+ *     that not setting this flag works properly only when the
+ *     %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because
+ *     otherwise the stack will not know when the DTIM beacon was sent.
+ *
+ * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED:
+ *     Channels are already configured to the default regulatory domain
+ *     specified in the device's EEPROM
+ */
+enum ieee80211_hw_flags {
+       IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE           = 1<<0,
+       IEEE80211_HW_RX_INCLUDES_FCS                    = 1<<1,
+       IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING        = 1<<2,
+       IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED      = 1<<3,
+};
+
+/**
+ * struct ieee80211_hw - hardware information and state
+ *
+ * This structure contains the configuration and hardware
+ * information for an 802.11 PHY.
+ *
+ * @wiphy: This points to the &struct wiphy allocated for this
+ *     802.11 PHY. You must fill in the @perm_addr and @dev
+ *     members of this structure using SET_IEEE80211_DEV()
+ *     and SET_IEEE80211_PERM_ADDR().
+ *
+ * @conf: &struct ieee80211_conf, device configuration, don't use.
+ *
+ * @workqueue: single threaded workqueue available for driver use,
+ *     allocated by mac80211 on registration and flushed on
+ *     unregistration.
+ *
+ * @priv: pointer to private area that was allocated for driver use
+ *     along with this structure.
+ *
+ * @flags: hardware flags, see &enum ieee80211_hw_flags.
+ *
+ * @extra_tx_headroom: headroom to reserve in each transmit skb
+ *     for use by the driver (e.g. for transmit headers.)
+ *
+ * @channel_change_time: time (in microseconds) it takes to change channels.
+ *
+ * @max_rssi: Maximum value for ssi in RX information, use
+ *     negative numbers for dBm and 0 to indicate no support.
+ *
+ * @max_signal: like @max_rssi, but for the signal value.
+ *
+ * @max_noise: like @max_rssi, but for the noise value.
+ *
+ * @queues: number of available hardware transmit queues for
+ *     data packets. WMM/QoS requires at least four.
+ */
+struct ieee80211_hw {
+       struct ieee80211_conf conf;
+       struct wiphy *wiphy;
+       struct workqueue_struct *workqueue;
+       void *priv;
+       u32 flags;
+       unsigned int extra_tx_headroom;
+       int channel_change_time;
+       u8 queues;
+       s8 max_rssi;
+       s8 max_signal;
+       s8 max_noise;
+};
+
+/**
+ * SET_IEEE80211_DEV - set device for 802.11 hardware
+ *
+ * @hw: the &struct ieee80211_hw to set the device for
+ * @dev: the &struct device of this 802.11 device
+ */
+static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev)
+{
+       set_wiphy_dev(hw->wiphy, dev);
+}
+
+/**
+ * SET_IEEE80211_PERM_ADDR - set the permanenet MAC address for 802.11 hardware
+ *
+ * @hw: the &struct ieee80211_hw to set the MAC address for
+ * @addr: the address to set
+ */
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+{
+       memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
+}
+
+/**
+ * DOC: Hardware crypto acceleration
+ *
+ * mac80211 is capable of taking advantage of many hardware
+ * acceleration designs for encryption and decryption operations.
+ *
+ * The set_key() callback in the &struct ieee80211_ops for a given
+ * device is called to enable hardware acceleration of encryption and
+ * decryption. The callback takes an @address parameter that will be
+ * the broadcast address for default keys, the other station's hardware
+ * address for individual keys or the zero address for keys that will
+ * be used only for transmission.
+ * Multiple transmission keys with the same key index may be used when
+ * VLANs are configured for an access point.
+ *
+ * The @local_address parameter will always be set to our own address,
+ * this is only relevant if you support multiple local addresses.
+ *
+ * When transmitting, the TX control data will use the @hw_key_idx
+ * selected by the driver by modifying the &struct ieee80211_key_conf
+ * pointed to by the @key parameter to the set_key() function.
+ *
+ * The set_key() call for the %SET_KEY command should return 0 if
+ * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be
+ * added; if you return 0 then hw_key_idx must be assigned to the
+ * hardware key index, you are free to use the full u8 range.
+ *
+ * When the cmd is %DISABLE_KEY then it must succeed.
+ *
+ * Note that it is permissible to not decrypt a frame even if a key
+ * for it has been uploaded to hardware, the stack will not make any
+ * decision based on whether a key has been uploaded or not but rather
+ * based on the receive flags.
+ *
+ * The &struct ieee80211_key_conf structure pointed to by the @key
+ * parameter is guaranteed to be valid until another call to set_key()
+ * removes it, but it can only be used as a cookie to differentiate
+ * keys.
+ */
+
+/**
+ * DOC: Frame filtering
+ *
+ * mac80211 requires to see many management frames for proper
+ * operation, and users may want to see many more frames when
+ * in monitor mode. However, for best CPU usage and power consumption,
+ * having as few frames as possible percolate through the stack is
+ * desirable. Hence, the hardware should filter as much as possible.
+ *
+ * To achieve this, mac80211 uses filter flags (see below) to tell
+ * the driver's configure_filter() function which frames should be
+ * passed to mac80211 and which should be filtered out.
+ *
+ * The configure_filter() callback is invoked with the parameters
+ * @mc_count and @mc_list for the combined multicast address list
+ * of all virtual interfaces, @changed_flags telling which flags
+ * were changed and @total_flags with the new flag states.
+ *
+ * If your device has no multicast address filters your driver will
+ * need to check both the %FIF_ALLMULTI flag and the @mc_count
+ * parameter to see whether multicast frames should be accepted
+ * or dropped.
+ *
+ * All unsupported flags in @total_flags must be cleared, i.e. you
+ * should clear all bits except those you honoured.
+ */
+
+/**
+ * enum ieee80211_filter_flags - hardware filter flags
+ *
+ * These flags determine what the filter in hardware should be
+ * programmed to let through and what should not be passed to the
+ * stack. It is always safe to pass more frames than requested,
+ * but this has negative impact on power consumption.
+ *
+ * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS,
+ *     think of the BSS as your network segment and then this corresponds
+ *     to the regular ethernet device promiscuous mode.
+ *
+ * @FIF_ALLMULTI: pass all multicast frames, this is used if requested
+ *     by the user or if the hardware is not capable of filtering by
+ *     multicast address.
+ *
+ * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the
+ *     %RX_FLAG_FAILED_FCS_CRC for them)
+ *
+ * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set
+ *     the %RX_FLAG_FAILED_PLCP_CRC for them
+ *
+ * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate
+ *     to the hardware that it should not filter beacons or probe responses
+ *     by BSSID. Filtering them can greatly reduce the amount of processing
+ *     mac80211 needs to do and the amount of CPU wakeups, so you should
+ *     honour this flag if possible.
+ *
+ * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then
+ *     only those addressed to this station
+ *
+ * @FIF_OTHER_BSS: pass frames destined to other BSSes
+ */
+enum ieee80211_filter_flags {
+       FIF_PROMISC_IN_BSS      = 1<<0,
+       FIF_ALLMULTI            = 1<<1,
+       FIF_FCSFAIL             = 1<<2,
+       FIF_PLCPFAIL            = 1<<3,
+       FIF_BCN_PRBRESP_PROMISC = 1<<4,
+       FIF_CONTROL             = 1<<5,
+       FIF_OTHER_BSS           = 1<<6,
+};
+
+/**
+ * enum ieee80211_erp_change_flags - erp change flags
+ *
+ * These flags are used with the erp_ie_changed() callback in
+ * &struct ieee80211_ops to indicate which parameter(s) changed.
+ * @IEEE80211_ERP_CHANGE_PROTECTION: protection changed
+ * @IEEE80211_ERP_CHANGE_PREAMBLE: barker preamble mode changed
+ */
+enum ieee80211_erp_change_flags {
+       IEEE80211_ERP_CHANGE_PROTECTION = 1<<0,
+       IEEE80211_ERP_CHANGE_PREAMBLE   = 1<<1,
+};
+
+
+/**
+ * struct ieee80211_ops - callbacks from mac80211 to the driver
+ *
+ * This structure contains various callbacks that the driver may
+ * handle or, in some cases, must handle, for example to configure
+ * the hardware to a new channel or to transmit a frame.
+ *
+ * @tx: Handler that 802.11 module calls for each transmitted frame.
+ *     skb contains the buffer starting from the IEEE 802.11 header.
+ *     The low-level driver should send the frame out based on
+ *     configuration in the TX control data. Must be implemented and
+ *     atomic.
+ *
+ * @start: Called before the first netdevice attached to the hardware
+ *     is enabled. This should turn on the hardware and must turn on
+ *     frame reception (for possibly enabled monitor interfaces.)
+ *     Returns negative error codes, these may be seen in userspace,
+ *     or zero.
+ *     When the device is started it should not have a MAC address
+ *     to avoid acknowledging frames before a non-monitor device
+ *     is added.
+ *     Must be implemented.
+ *
+ * @stop: Called after last netdevice attached to the hardware
+ *     is disabled. This should turn off the hardware (at least
+ *     it must turn off frame reception.)
+ *     May be called right after add_interface if that rejects
+ *     an interface.
+ *     Must be implemented.
+ *
+ * @add_interface: Called when a netdevice attached to the hardware is
+ *     enabled. Because it is not called for monitor mode devices, @open
+ *     and @stop must be implemented.
+ *     The driver should perform any initialization it needs before
+ *     the device can be enabled. The initial configuration for the
+ *     interface is given in the conf parameter.
+ *     The callback may refuse to add an interface by returning a
+ *     negative error code (which will be seen in userspace.)
+ *     Must be implemented.
+ *
+ * @remove_interface: Notifies a driver that an interface is going down.
+ *     The @stop callback is called after this if it is the last interface
+ *     and no monitor interfaces are present.
+ *     When all interfaces are removed, the MAC address in the hardware
+ *     must be cleared so the device no longer acknowledges packets,
+ *     the mac_addr member of the conf structure is, however, set to the
+ *     MAC address of the device going away.
+ *     Hence, this callback must be implemented.
+ *
+ * @config: Handler for configuration requests. IEEE 802.11 code calls this
+ *     function to change hardware configuration, e.g., channel.
+ *
+ * @config_interface: Handler for configuration requests related to interfaces
+ *     (e.g. BSSID changes.)
+ *
+ * @configure_filter: Configure the device's RX filter.
+ *     See the section "Frame filtering" for more information.
+ *     This callback must be implemented and atomic.
+ *
+ * @set_tim: Set TIM bit. If the hardware/firmware takes care of beacon
+ *     generation (that is, %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is set)
+ *     mac80211 calls this function when a TIM bit must be set or cleared
+ *     for a given AID. Must be atomic.
+ *
+ * @set_key: See the section "Hardware crypto acceleration"
+ *     This callback can sleep, and is only called between add_interface
+ *     and remove_interface calls, i.e. while the interface with the
+ *     given local_address is enabled.
+ *
+ * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card
+ *     to pass unencrypted EAPOL-Key frames even when encryption is
+ *     configured. If the wlan card does not require such a configuration,
+ *     this function pointer can be set to NULL.
+ *
+ * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be
+ *     authorized (@authorized=1) or unauthorized (=0). This function can be
+ *     used if the wlan hardware or low-level driver implements PAE.
+ *     mac80211 will filter frames based on authorization state in any case,
+ *     so this function pointer can be NULL if low-level driver does not
+ *     require event notification about port state changes.
+ *
+ * @hw_scan: Ask the hardware to service the scan request, no need to start
+ *     the scan state machine in stack.
+ *
+ * @get_stats: return low-level statistics
+ *
+ * @set_privacy_invoked: For devices that generate their own beacons and probe
+ *     response or association responses this updates the state of privacy_invoked
+ *     returns 0 for success or an error number.
+ *
+ * @get_sequence_counter: For devices that have internal sequence counters this
+ *     callback allows mac80211 to access the current value of a counter.
+ *     This callback seems not well-defined, tell us if you need it.
+ *
+ * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
+ *
+ * @set_frag_threshold: Configuration of fragmentation threshold. Assign this if
+ *     the device does fragmentation by itself; if this method is assigned then
+ *     the stack will not do fragmentation.
+ *
+ * @set_retry_limit: Configuration of retry limits (if device needs it)
+ *
+ * @sta_notify: Notifies low level driver about addition or removal
+ *     of assocaited station or AP.
+ *
+ * @erp_ie_changed: Handle ERP IE change notifications. Must be atomic.
+ *
+ * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
+ *     bursting) for a hardware TX queue. The @queue parameter uses the
+ *     %IEEE80211_TX_QUEUE_* constants. Must be atomic.
+ *
+ * @get_tx_stats: Get statistics of the current TX queue status. This is used
+ *     to get number of currently queued packets (queue length), maximum queue
+ *     size (limit), and total number of packets sent using each TX queue
+ *     (count). This information is used for WMM to find out which TX
+ *     queues have room for more packets and by hostapd to provide
+ *     statistics about the current queueing state to external programs.
+ *
+ * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
+ *     this is only used for IBSS mode debugging and, as such, is not a
+ *     required function. Must be atomic.
+ *
+ * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
+ *     with other STAs in the IBSS. This is only used in IBSS mode. This
+ *     function is optional if the firmware/hardware takes full care of
+ *     TSF synchronization.
+ *
+ * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point,
+ *     IBSS uses a fixed beacon frame which is configured using this
+ *     function.
+ *     If the driver returns success (0) from this callback, it owns
+ *     the skb. That means the driver is responsible to kfree_skb() it.
+ *     The control structure is not dynamically allocated. That means the
+ *     driver does not own the pointer and if it needs it somewhere
+ *     outside of the context of this function, it must copy it
+ *     somewhere else.
+ *     This handler is required only for IBSS mode.
+ *
+ * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
+ *     This is needed only for IBSS mode and the result of this function is
+ *     used to determine whether to reply to Probe Requests.
+ */
+struct ieee80211_ops {
+       int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
+                 struct ieee80211_tx_control *control);
+       int (*start)(struct ieee80211_hw *hw);
+       void (*stop)(struct ieee80211_hw *hw);
+       int (*add_interface)(struct ieee80211_hw *hw,
+                            struct ieee80211_if_init_conf *conf);
+       void (*remove_interface)(struct ieee80211_hw *hw,
+                                struct ieee80211_if_init_conf *conf);
+       int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+       int (*config_interface)(struct ieee80211_hw *hw,
+                               int if_id, struct ieee80211_if_conf *conf);
+       void (*configure_filter)(struct ieee80211_hw *hw,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_addr_list *mc_list);
+       int (*set_tim)(struct ieee80211_hw *hw, int aid, int set);
+       int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                      const u8 *local_address, const u8 *address,
+                      struct ieee80211_key_conf *key);
+       int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
+       int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
+                            int authorized);
+       int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
+       int (*get_stats)(struct ieee80211_hw *hw,
+                        struct ieee80211_low_level_stats *stats);
+       int (*set_privacy_invoked)(struct ieee80211_hw *hw,
+                                  int privacy_invoked);
+       int (*get_sequence_counter)(struct ieee80211_hw *hw,
+                                   u8* addr, u8 keyidx, u8 txrx,
+                                   u32* iv32, u16* iv16);
+       int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
+       int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
+       int (*set_retry_limit)(struct ieee80211_hw *hw,
+                              u32 short_retry, u32 long_retr);
+       void (*sta_notify)(struct ieee80211_hw *hw, int if_id,
+                       enum sta_notify_cmd, const u8 *addr);
+       void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes,
+                              int cts_protection, int preamble);
+       int (*conf_tx)(struct ieee80211_hw *hw, int queue,
+                      const struct ieee80211_tx_queue_params *params);
+       int (*get_tx_stats)(struct ieee80211_hw *hw,
+                           struct ieee80211_tx_queue_stats *stats);
+       u64 (*get_tsf)(struct ieee80211_hw *hw);
+       void (*reset_tsf)(struct ieee80211_hw *hw);
+       int (*beacon_update)(struct ieee80211_hw *hw,
+                            struct sk_buff *skb,
+                            struct ieee80211_tx_control *control);
+       int (*tx_last_beacon)(struct ieee80211_hw *hw);
+};
+
+/**
+ * ieee80211_alloc_hw -  Allocate a new hardware device
+ *
+ * This must be called once for each hardware device. The returned pointer
+ * must be used to refer to this device when calling other functions.
+ * mac80211 allocates a private data area for the driver pointed to by
+ * @priv in &struct ieee80211_hw, the size of this area is given as
+ * @priv_data_len.
+ *
+ * @priv_data_len: length of private data
+ * @ops: callbacks for this device
+ */
+struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
+                                       const struct ieee80211_ops *ops);
+
+/**
+ * ieee80211_register_hw - Register hardware device
+ *
+ * You must call this function before any other functions
+ * except ieee80211_register_hwmode.
+ *
+ * @hw: the device to register as returned by ieee80211_alloc_hw()
+ */
+int ieee80211_register_hw(struct ieee80211_hw *hw);
+
+#ifdef CONFIG_MAC80211_LEDS
+extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
+extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
+extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
+#endif
+/**
+ * ieee80211_get_tx_led_name - get name of TX LED
+ *
+ * mac80211 creates a transmit LED trigger for each wireless hardware
+ * that can be used to drive LEDs if your driver registers a LED device.
+ * This function returns the name (or %NULL if not configured for LEDs)
+ * of the trigger so you can automatically link the LED device.
+ *
+ * @hw: the hardware to get the LED trigger name for
+ */
+static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       return __ieee80211_get_tx_led_name(hw);
+#else
+       return NULL;
+#endif
+}
+
+/**
+ * ieee80211_get_rx_led_name - get name of RX LED
+ *
+ * mac80211 creates a receive LED trigger for each wireless hardware
+ * that can be used to drive LEDs if your driver registers a LED device.
+ * This function returns the name (or %NULL if not configured for LEDs)
+ * of the trigger so you can automatically link the LED device.
+ *
+ * @hw: the hardware to get the LED trigger name for
+ */
+static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       return __ieee80211_get_rx_led_name(hw);
+#else
+       return NULL;
+#endif
+}
+
+static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       return __ieee80211_get_assoc_led_name(hw);
+#else
+       return NULL;
+#endif
+}
+
+
+/* Register a new hardware PHYMODE capability to the stack. */
+int ieee80211_register_hwmode(struct ieee80211_hw *hw,
+                             struct ieee80211_hw_mode *mode);
+
+/**
+ * ieee80211_unregister_hw - Unregister a hardware device
+ *
+ * This function instructs mac80211 to free allocated resources
+ * and unregister netdevices from the networking subsystem.
+ *
+ * @hw: the hardware to unregister
+ */
+void ieee80211_unregister_hw(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_free_hw - free hardware descriptor
+ *
+ * This function frees everything that was allocated, including the
+ * private data for the driver. You must call ieee80211_unregister_hw()
+ * before calling this function
+ *
+ * @hw: the hardware to free
+ */
+void ieee80211_free_hw(struct ieee80211_hw *hw);
+
+/* trick to avoid symbol clashes with the ieee80211 subsystem */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                   struct ieee80211_rx_status *status);
+
+/**
+ * ieee80211_rx - receive frame
+ *
+ * Use this function to hand received frames to mac80211. The receive
+ * buffer in @skb must start with an IEEE 802.11 header or a radiotap
+ * header if %RX_FLAG_RADIOTAP is set in the @status flags.
+ *
+ * This function may not be called in IRQ context.
+ *
+ * @hw: the hardware this frame came in on
+ * @skb: the buffer to receive, owned by mac80211 after this call
+ * @status: status of this frame; the status pointer need not be valid
+ *     after this function returns
+ */
+static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                               struct ieee80211_rx_status *status)
+{
+       __ieee80211_rx(hw, skb, status);
+}
+
+/**
+ * ieee80211_rx_irqsafe - receive frame
+ *
+ * Like ieee80211_rx() but can be called in IRQ context
+ * (internally defers to a workqueue.)
+ *
+ * @hw: the hardware this frame came in on
+ * @skb: the buffer to receive, owned by mac80211 after this call
+ * @status: status of this frame; the status pointer need not be valid
+ *     after this function returns and is not freed by mac80211,
+ *     it is recommended that it points to a stack area
+ */
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
+                         struct sk_buff *skb,
+                         struct ieee80211_rx_status *status);
+
+/**
+ * ieee80211_tx_status - transmit status callback
+ *
+ * Call this function for all transmitted frames after they have been
+ * transmitted. It is permissible to not call this function for
+ * multicast frames but this can affect statistics.
+ *
+ * @hw: the hardware the frame was transmitted by
+ * @skb: the frame that was transmitted, owned by mac80211 after this call
+ * @status: status information for this frame; the status pointer need not
+ *     be valid after this function returns and is not freed by mac80211,
+ *     it is recommended that it points to a stack area
+ */
+void ieee80211_tx_status(struct ieee80211_hw *hw,
+                        struct sk_buff *skb,
+                        struct ieee80211_tx_status *status);
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+                                struct sk_buff *skb,
+                                struct ieee80211_tx_status *status);
+
+/**
+ * ieee80211_beacon_get - beacon generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send this beacon.
+ *
+ * If the beacon frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next beacon frame from the 802.11 code. The low-level is responsible
+ * for calling this function before beacon data is needed (e.g., based on
+ * hardware interrupt). Returned skb is used only once and low-level driver
+ * is responsible of freeing it.
+ */
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
+                                    int if_id,
+                                    struct ieee80211_tx_control *control);
+
+/**
+ * ieee80211_rts_get - RTS frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @frame: pointer to the frame that is going to be protected by the RTS.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @rts: The buffer where to store the RTS frame.
+ *
+ * If the RTS frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next RTS frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and RTS frame is needed.
+ */
+void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
+                      const void *frame, size_t frame_len,
+                      const struct ieee80211_tx_control *frame_txctl,
+                      struct ieee80211_rts *rts);
+
+/**
+ * ieee80211_rts_duration - Get the duration field for an RTS frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @frame_len: the length of the frame that is going to be protected by the RTS.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the RTS is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
+                             size_t frame_len,
+                             const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_ctstoself_get - CTS-to-self frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @cts: The buffer where to store the CTS-to-self frame.
+ *
+ * If the CTS-to-self frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and CTS-to-self frame is needed.
+ */
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
+                            const void *frame, size_t frame_len,
+                            const struct ieee80211_tx_control *frame_txctl,
+                            struct ieee80211_cts *cts);
+
+/**
+ * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the CTS-to-self is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
+                                   size_t frame_len,
+                                   const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_generic_frame_duration - Calculate the duration field for a frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @frame_len: the length of the frame.
+ * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
+ *
+ * Calculate the duration field of some generic frame, given its
+ * length and transmission rate (in 100kbps).
+ */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
+                                       size_t frame_len,
+                                       int rate);
+
+/**
+ * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send returned frame.
+ *
+ * Function for accessing buffered broadcast and multicast frames. If
+ * hardware/firmware does not implement buffering of broadcast/multicast
+ * frames when power saving is used, 802.11 code buffers them in the host
+ * memory. The low-level driver uses this function to fetch next buffered
+ * frame. In most cases, this is used when generating beacon frame. This
+ * function returns a pointer to the next buffered skb or NULL if no more
+ * buffered frames are available.
+ *
+ * Note: buffered frames are returned only after DTIM beacon frame was
+ * generated with ieee80211_beacon_get() and the low-level driver must thus
+ * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns
+ * NULL if the previous generated beacon was not DTIM, so the low-level driver
+ * does not need to check for DTIM beacons separately and should be able to
+ * use common code for all beacons.
+ */
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+                         struct ieee80211_tx_control *control);
+
+/**
+ * ieee80211_get_hdrlen_from_skb - get header length from data
+ *
+ * Given an skb with a raw 802.11 header at the data pointer this function
+ * returns the 802.11 header length in bytes (not including encryption
+ * headers). If the data in the sk_buff is too short to contain a valid 802.11
+ * header the function returns 0.
+ *
+ * @skb: the frame
+ */
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
+
+/**
+ * ieee80211_get_hdrlen - get header length from frame control
+ *
+ * This function returns the 802.11 header length in bytes (not including
+ * encryption headers.)
+ *
+ * @fc: the frame control field (in CPU endianness)
+ */
+int ieee80211_get_hdrlen(u16 fc);
+
+/**
+ * ieee80211_wake_queue - wake specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_stop_queue - stop specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_start_queues - start all queues
+ * @hw: pointer to as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_start_queue.
+ */
+void ieee80211_start_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_stop_queues - stop all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_wake_queues - wake all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_scan_completed - completed hardware scan
+ *
+ * When hardware scan offload is used (i.e. the hw_scan() callback is
+ * assigned) this function needs to be called by the driver to notify
+ * mac80211 that the scan finished.
+ *
+ * @hw: the hardware that finished the scan
+ */
+void ieee80211_scan_completed(struct ieee80211_hw *hw);
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
+                  ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+
+#endif /* MAC80211_H */
index a03c886a6c6b879a51ae445155ae80cbeb76defc..6fffb3845ab6c76b341819376def9f1c77e68424 100644 (file)
@@ -64,10 +64,6 @@ config MAC80211_DEBUG_COUNTERS
        bool "Extra statistics for TX/RX debugging"
        depends on MAC80211_DEBUG
 
-config HOSTAPD_WPA_TESTING
-       bool "Support for TKIP countermeasures testing"
-       depends on MAC80211_DEBUG
-
 config MAC80211_IBSS_DEBUG
        bool "Support for IBSS testing"
        depends on MAC80211_DEBUG
index 0a88dd312a445f4588e1f037da09ed64ab2492e4..219cd9f9341fe099bc0ce5ba69c2da7442339ab8 100644 (file)
@@ -1,7 +1,8 @@
-obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o rc80211_lowest.o
+obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
 
 mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
 mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
+mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
 
 mac80211-objs := \
        ieee80211.o \
@@ -16,6 +17,10 @@ mac80211-objs := \
        regdomain.o \
        tkip.o \
        aes_ccm.o \
-       wme.o \
-       ieee80211_cfg.o \
+       cfg.o \
+       rx.o \
+       tx.o \
+       key.o \
+       util.o \
+       event.o \
        $(mac80211-objs-y)
diff --git a/package/mac80211/src/mac80211/cfg.c b/package/mac80211/src/mac80211/cfg.c
new file mode 100644 (file)
index 0000000..cd78b3f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ *
+ * Copyright 2006      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is GPLv2 as found in COPYING.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+#include "cfg.h"
+
+static enum ieee80211_if_types
+nl80211_type_to_mac80211_type(enum nl80211_iftype type)
+{
+       switch (type) {
+       case NL80211_IFTYPE_UNSPECIFIED:
+               return IEEE80211_IF_TYPE_STA;
+       case NL80211_IFTYPE_ADHOC:
+               return IEEE80211_IF_TYPE_IBSS;
+       case NL80211_IFTYPE_STATION:
+               return IEEE80211_IF_TYPE_STA;
+       case NL80211_IFTYPE_MONITOR:
+               return IEEE80211_IF_TYPE_MNTR;
+       default:
+               return IEEE80211_IF_TYPE_INVALID;
+       }
+}
+
+static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
+                              enum nl80211_iftype type)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       enum ieee80211_if_types itype;
+
+       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+               return -ENODEV;
+
+       itype = nl80211_type_to_mac80211_type(type);
+       if (itype == IEEE80211_IF_TYPE_INVALID)
+               return -EINVAL;
+
+       return ieee80211_if_add(local->mdev, name, NULL, itype);
+}
+
+static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct net_device *dev;
+       char *name;
+
+       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+               return -ENODEV;
+
+       /* we're under RTNL */
+       dev = __dev_get_by_index(ifindex);
+       if (!dev)
+               return 0;
+
+       name = dev->name;
+
+       return ieee80211_if_remove(local->mdev, name, -1);
+}
+
+static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
+                                 enum nl80211_iftype type)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct net_device *dev;
+       enum ieee80211_if_types itype;
+       struct ieee80211_sub_if_data *sdata;
+
+       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+               return -ENODEV;
+
+       /* we're under RTNL */
+       dev = __dev_get_by_index(ifindex);
+       if (!dev)
+               return -ENODEV;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       itype = nl80211_type_to_mac80211_type(type);
+       if (itype == IEEE80211_IF_TYPE_INVALID)
+               return -EINVAL;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+        if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+               return -EOPNOTSUPP;
+
+       ieee80211_if_reinit(dev);
+       ieee80211_if_set_type(dev, itype);
+
+       return 0;
+}
+
+struct cfg80211_ops mac80211_config_ops = {
+       .add_virtual_intf = ieee80211_add_iface,
+       .del_virtual_intf = ieee80211_del_iface,
+       .change_virtual_intf = ieee80211_change_iface,
+};
diff --git a/package/mac80211/src/mac80211/cfg.h b/package/mac80211/src/mac80211/cfg.h
new file mode 100644 (file)
index 0000000..7d7879f
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ */
+#ifndef __CFG_H
+#define __CFG_H
+
+extern struct cfg80211_ops mac80211_config_ops;
+
+#endif /* __CFG_H */
index 07e643ac24b97bf9c1b85d24363e06fb93a44e84..60514b2c97b99c845eac2020a9f865557a59f170 100644 (file)
 #include "ieee80211_rate.h"
 #include "debugfs.h"
 
-static inline int rtnl_lock_local(struct ieee80211_local *local)
-{
-       rtnl_lock();
-       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
-               rtnl_unlock();
-               return -ENODEV;
-       }
-       return 0;
-}
-
 int mac80211_open_file_generic(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
@@ -38,8 +28,6 @@ static const char *ieee80211_mode_str(int mode)
                return "IEEE 802.11b";
        case MODE_IEEE80211G:
                return "IEEE 802.11g";
-       case MODE_ATHEROS_TURBO:
-               return "Atheros Turbo (5 GHz)";
        default:
                return "UNKNOWN";
        }
@@ -66,7 +54,7 @@ static const struct file_operations modes_ops = {
        .open = mac80211_open_file_generic,
 };
 
-#define DEBUGFS_READ(name, buflen, fmt, value...)                      \
+#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)             \
 static ssize_t name## _read(struct file *file, char __user *userbuf,   \
                            size_t count, loff_t *ppos)                 \
 {                                                                      \
@@ -77,20 +65,16 @@ static ssize_t name## _read(struct file *file, char __user *userbuf,        \
        res = scnprintf(buf, buflen, fmt "\n", ##value);                \
        return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
 }                                                                      \
-
-#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)             \
-DEBUGFS_READ(name, buflen, fmt, ## value)                              \
+                                                                       \
 static const struct file_operations name## _ops = {                    \
        .read = name## _read,                                           \
        .open = mac80211_open_file_generic,                             \
 };
 
-#define DEBUGFS_ADD_MODE(name, mode)                                   \
-       local->debugfs.name = debugfs_create_file(#name, mode, phyd,    \
+#define DEBUGFS_ADD(name)                                              \
+       local->debugfs.name = debugfs_create_file(#name, 0444, phyd,    \
                                                  local, &name## _ops);
 
-#define DEBUGFS_ADD(name)      DEBUGFS_ADD_MODE(name, 0444)
-
 #define DEBUGFS_DEL(name)                                              \
        debugfs_remove(local->debugfs.name);                            \
        local->debugfs.name = NULL;
@@ -100,16 +84,12 @@ DEBUGFS_READONLY_FILE(channel, 20, "%d",
                      local->hw.conf.channel);
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
                      local->hw.conf.freq);
-DEBUGFS_READONLY_FILE(radar_detect, 20, "%d",
-                     local->hw.conf.radar_detect);
 DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
                      local->hw.conf.antenna_sel_tx);
 DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
                      local->hw.conf.antenna_sel_rx);
 DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d",
                      local->bridge_packets);
-DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d",
-                     local->key_tx_rx_threshold);
 DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
                      local->rts_threshold);
 DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -124,41 +104,21 @@ DEBUGFS_READONLY_FILE(mode, 20, "%s",
                      ieee80211_mode_str(local->hw.conf.phymode));
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
                      local->wep_iv & 0xffffff);
-DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm",
-                     local->hw.conf.tx_power_reduction / 10,
-                     local->hw.conf.tx_power_reduction & 10);
+DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
+                     local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
 
-DEBUGFS_READ(rate_ctrl_alg, 100, "%s",
-            local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+/* statistics stuff */
 
-static ssize_t rate_ctrl_alg_write(struct file *file, const char __user *userbuf,
-                                  size_t count, loff_t *ppos)
+static inline int rtnl_lock_local(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local = file->private_data;
-       char buf[64];
-       ssize_t buf_size;
-       int res;
-
-       buf_size = min(count, ARRAY_SIZE(buf) - 1);
-       if (copy_from_user(buf, userbuf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = '\0';
-       res = rtnl_lock_local(local);
-       if (res)
-               return res;
-       res = ieee80211_init_rate_ctrl_alg(local, buf);
-       rtnl_unlock();
-       return res < 0 ? res : buf_size;
+       rtnl_lock();
+       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+               rtnl_unlock();
+               return -ENODEV;
+       }
+       return 0;
 }
 
-static const struct file_operations rate_ctrl_alg_ops = {
-       .read = rate_ctrl_alg_read,
-       .write = rate_ctrl_alg_write,
-       .open = mac80211_open_file_generic,
-};
-
-/* statistics stuff */
-
 #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)                        \
        DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
 
@@ -336,11 +296,9 @@ void debugfs_hw_add(struct ieee80211_local *local)
 
        DEBUGFS_ADD(channel);
        DEBUGFS_ADD(frequency);
-       DEBUGFS_ADD(radar_detect);
        DEBUGFS_ADD(antenna_sel_tx);
        DEBUGFS_ADD(antenna_sel_rx);
        DEBUGFS_ADD(bridge_packets);
-       DEBUGFS_ADD(key_tx_rx_threshold);
        DEBUGFS_ADD(rts_threshold);
        DEBUGFS_ADD(fragmentation_threshold);
        DEBUGFS_ADD(short_retry_limit);
@@ -348,8 +306,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(total_ps_buffered);
        DEBUGFS_ADD(mode);
        DEBUGFS_ADD(wep_iv);
-       DEBUGFS_ADD(tx_power_reduction);
-       DEBUGFS_ADD_MODE(rate_ctrl_alg, 0644);
        DEBUGFS_ADD(modes);
 
        statsd = debugfs_create_dir("statistics", phyd);
@@ -402,11 +358,9 @@ void debugfs_hw_del(struct ieee80211_local *local)
 {
        DEBUGFS_DEL(channel);
        DEBUGFS_DEL(frequency);
-       DEBUGFS_DEL(radar_detect);
        DEBUGFS_DEL(antenna_sel_tx);
        DEBUGFS_DEL(antenna_sel_rx);
        DEBUGFS_DEL(bridge_packets);
-       DEBUGFS_DEL(key_tx_rx_threshold);
        DEBUGFS_DEL(rts_threshold);
        DEBUGFS_DEL(fragmentation_threshold);
        DEBUGFS_DEL(short_retry_limit);
@@ -414,8 +368,6 @@ void debugfs_hw_del(struct ieee80211_local *local)
        DEBUGFS_DEL(total_ps_buffered);
        DEBUGFS_DEL(mode);
        DEBUGFS_DEL(wep_iv);
-       DEBUGFS_DEL(tx_power_reduction);
-       DEBUGFS_DEL(rate_ctrl_alg);
        DEBUGFS_DEL(modes);
 
        DEBUGFS_STATS_DEL(transmitted_fragment_count);
index 7d56dc9e7326fb32deb9fb19b9a84afb4b191b22..8e4a1bcd16ea3cf4466759c2216cc7f0ce3a35ca 100644 (file)
 #include "debugfs.h"
 #include "debugfs_key.h"
 
-#define KEY_READ(name, buflen, format_string)                          \
+#define KEY_READ(name, prop, buflen, format_string)                    \
 static ssize_t key_##name##_read(struct file *file,                    \
                                 char __user *userbuf,                  \
                                 size_t count, loff_t *ppos)            \
 {                                                                      \
        char buf[buflen];                                               \
        struct ieee80211_key *key = file->private_data;                 \
-       int res = scnprintf(buf, buflen, format_string, key->name);     \
+       int res = scnprintf(buf, buflen, format_string, key->prop);     \
        return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
 }
-#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n")
+#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n")
+#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n")
 
 #define KEY_OPS(name)                                                  \
 static const struct file_operations key_ ##name## _ops = {             \
@@ -36,11 +37,27 @@ static const struct file_operations key_ ##name## _ops = {          \
                 KEY_READ_##format(name)                                \
                 KEY_OPS(name)
 
-KEY_FILE(keylen, D);
-KEY_FILE(force_sw_encrypt, D);
-KEY_FILE(keyidx, D);
-KEY_FILE(hw_key_idx, D);
+#define KEY_CONF_READ(name, buflen, format_string)                     \
+       KEY_READ(conf_##name, conf.name, buflen, format_string)
+#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n")
+
+#define KEY_CONF_OPS(name)                                             \
+static const struct file_operations key_ ##name## _ops = {             \
+       .read = key_conf_##name##_read,                                 \
+       .open = mac80211_open_file_generic,                             \
+}
+
+#define KEY_CONF_FILE(name, format)                                    \
+                KEY_CONF_READ_##format(name)                           \
+                KEY_CONF_OPS(name)
+
+KEY_CONF_FILE(keylen, D);
+KEY_CONF_FILE(keyidx, D);
+KEY_CONF_FILE(hw_key_idx, D);
+KEY_FILE(flags, X);
 KEY_FILE(tx_rx_count, D);
+KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n");
+KEY_OPS(ifindex);
 
 static ssize_t key_algorithm_read(struct file *file,
                                  char __user *userbuf,
@@ -49,7 +66,7 @@ static ssize_t key_algorithm_read(struct file *file,
        char *alg;
        struct ieee80211_key *key = file->private_data;
 
-       switch (key->alg) {
+       switch (key->conf.alg) {
        case ALG_WEP:
                alg = "WEP\n";
                break;
@@ -74,17 +91,20 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
        int len;
        struct ieee80211_key *key = file->private_data;
 
-       switch (key->alg) {
+       switch (key->conf.alg) {
        case ALG_WEP:
                len = scnprintf(buf, sizeof(buf), "\n");
+               break;
        case ALG_TKIP:
                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
                                key->u.tkip.iv32,
                                key->u.tkip.iv16);
+               break;
        case ALG_CCMP:
                tpn = key->u.ccmp.tx_pn;
                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
                                tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
+               break;
        default:
                return 0;
        }
@@ -100,9 +120,10 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
        int i, len;
        const u8 *rpn;
 
-       switch (key->alg) {
+       switch (key->conf.alg) {
        case ALG_WEP:
                len = scnprintf(buf, sizeof(buf), "\n");
+               break;
        case ALG_TKIP:
                for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p,
@@ -110,6 +131,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                                       key->u.tkip.iv32_rx[i],
                                       key->u.tkip.iv16_rx[i]);
                len = p - buf;
+               break;
        case ALG_CCMP:
                for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
                        rpn = key->u.ccmp.rx_pn[i];
@@ -119,6 +141,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                                       rpn[3], rpn[4], rpn[5]);
                }
                len = p - buf;
+               break;
        default:
                return 0;
        }
@@ -133,7 +156,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
        char buf[20];
        int len;
 
-       if (key->alg != ALG_CCMP)
+       if (key->conf.alg != ALG_CCMP)
                return 0;
        len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
@@ -144,12 +167,12 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf,
                            size_t count, loff_t *ppos)
 {
        struct ieee80211_key *key = file->private_data;
-       int i, res, bufsize = 2*key->keylen+2;
+       int i, res, bufsize = 2 * key->conf.keylen + 2;
        char *buf = kmalloc(bufsize, GFP_KERNEL);
        char *p = buf;
 
-       for (i = 0; i < key->keylen; i++)
-               p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]);
+       for (i = 0; i < key->conf.keylen; i++)
+               p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
        p += scnprintf(p, bufsize+buf-p, "\n");
        res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
        kfree(buf);
@@ -164,12 +187,14 @@ KEY_OPS(key);
 void ieee80211_debugfs_key_add(struct ieee80211_local *local,
                               struct ieee80211_key *key)
 {
+       static int keycount;
        char buf[20];
 
        if (!local->debugfs.keys)
                return;
 
-       sprintf(buf, "%d", key->keyidx);
+       sprintf(buf, "%d", keycount);
+       keycount++;
        key->debugfs.dir = debugfs_create_dir(buf,
                                        local->debugfs.keys);
 
@@ -177,7 +202,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local,
                return;
 
        DEBUGFS_ADD(keylen);
-       DEBUGFS_ADD(force_sw_encrypt);
+       DEBUGFS_ADD(flags);
        DEBUGFS_ADD(keyidx);
        DEBUGFS_ADD(hw_key_idx);
        DEBUGFS_ADD(tx_rx_count);
@@ -186,6 +211,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local,
        DEBUGFS_ADD(rx_spec);
        DEBUGFS_ADD(replays);
        DEBUGFS_ADD(key);
+       DEBUGFS_ADD(ifindex);
 };
 
 #define DEBUGFS_DEL(name) \
@@ -197,7 +223,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
                return;
 
        DEBUGFS_DEL(keylen);
-       DEBUGFS_DEL(force_sw_encrypt);
+       DEBUGFS_DEL(flags);
        DEBUGFS_DEL(keyidx);
        DEBUGFS_DEL(hw_key_idx);
        DEBUGFS_DEL(tx_rx_count);
@@ -206,6 +232,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
        DEBUGFS_DEL(rx_spec);
        DEBUGFS_DEL(replays);
        DEBUGFS_DEL(key);
+       DEBUGFS_DEL(ifindex);
 
        debugfs_remove(key->debugfs.stalink);
        key->debugfs.stalink = NULL;
@@ -219,7 +246,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
        if (!sdata->debugfsdir)
                return;
 
-       sprintf(buf, "../keys/%d", sdata->default_key->keyidx);
+       sprintf(buf, "../keys/%d", sdata->default_key->conf.keyidx);
        sdata->debugfs.default_key =
                debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
 }
@@ -239,7 +266,7 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
        if (!key->debugfs.dir)
                return;
 
-       sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr));
+       sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr));
        key->debugfs.stalink =
                debugfs_create_symlink("station", key->debugfs.dir, buf);
 }
index 52a32e4f6a227a6fe3e1f7ee2daf04399c06ba69..2b5e7615e5091d00c41d13b6ceb7a21b1d07b061 100644 (file)
@@ -87,267 +87,6 @@ static const struct file_operations name##_ops = {                  \
                IEEE80211_IF_FMT_##format(name, field)                  \
                __IEEE80211_IF_FILE(name)
 
-#define DEBUGFS_QOS_FILE(name, f)                                      \
-static ssize_t qos_ ##name## _write(struct file *file,                 \
-                                   const char __user *userbuf,         \
-                                   size_t count, loff_t *ppos)         \
-{                                                                      \
-       struct ieee80211_sub_if_data *sdata = file->private_data;       \
-                                                                       \
-       f(sdata->dev, &sdata->u.sta, &sdata->u.sta.tspec);              \
-                                                                       \
-       return count;                                                   \
-}                                                                      \
-                                                                       \
-static const struct file_operations qos_ ##name## _ops = {             \
-       .write = qos_ ##name## _write,                                  \
-       .open = mac80211_open_file_generic,                             \
-};
-
-#define DEBUGFS_QOS_ADD(name)                                          \
-       sdata->debugfs.sta.qos.name = debugfs_create_file(#name, 0444, qosd,\
-               sdata, &qos_ ##name## _ops);
-
-#define DEBUGFS_QOS_DEL(name)                                          \
-       do {                                                            \
-               debugfs_remove(sdata->debugfs.sta.qos.name);            \
-               sdata->debugfs.sta.qos.name = NULL;                     \
-       } while (0)
-
-DEBUGFS_QOS_FILE(addts_11e, ieee80211_send_addts);
-DEBUGFS_QOS_FILE(addts_wmm, wmm_send_addts);
-DEBUGFS_QOS_FILE(delts_11e, ieee80211_send_delts);
-DEBUGFS_QOS_FILE(delts_wmm, wmm_send_delts);
-
-static ssize_t qos_if_dls_mac(const struct ieee80211_sub_if_data *sdata,
-                             char *buf, int buflen)
-{
-       return scnprintf(buf, buflen, MAC_FMT "\n",
-                        MAC_ARG(sdata->u.sta.dls_mac));
-}
-
-static ssize_t qos_dls_mac_read(struct file *file,
-                               char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       return ieee80211_if_read(file->private_data,
-                                userbuf, count, ppos,
-                                qos_if_dls_mac);
-}
-
-static ssize_t qos_dls_mac_write(struct file *file, const char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       struct ieee80211_sub_if_data *sdata = file->private_data;
-       char buf[20];
-       size_t size;
-       u8 m[ETH_ALEN];
-
-       size = min(sizeof(buf) - 1, count);
-       buf[size] = '\0';
-       if (copy_from_user(buf, userbuf, size))
-               return -EFAULT;
-
-       if (sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
-                  &((u8*)(m))[0], &((u8*)(m))[1], &((u8*)(m))[2],
-                  &((u8*)(m))[3], &((u8*)(m))[4], &((u8*)(m))[5]) != ETH_ALEN){
-               printk(KERN_ERR "%s: sscanf input error\n", sdata->dev->name);
-               return -EINVAL;
-       }
-       memcpy(sdata->u.sta.dls_mac, m, ETH_ALEN);
-       return count;
-}
-
-static const struct file_operations qos_dls_mac_ops = {
-       .read = qos_dls_mac_read,
-       .write = qos_dls_mac_write,
-       .open = mac80211_open_file_generic,
-};
-
-static ssize_t qos_if_dls_op(const struct ieee80211_sub_if_data *sdata,
-                            char *buf, int buflen)
-{
-       return scnprintf(buf, buflen,
-                        "DLS Operation: Setup = 1; Teardown = 2\n");
-}
-
-static ssize_t qos_dls_op_read(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       return ieee80211_if_read(file->private_data,
-                                userbuf, count, ppos,
-                                qos_if_dls_op);
-}
-
-static ssize_t qos_dls_op_write(struct file *file, const char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       struct ieee80211_sub_if_data *sdata = file->private_data;
-       char buf[20];
-       size_t size;
-       unsigned int opt;
-
-       size = min(sizeof(buf) - 1, count);
-       buf[size] = '\0';
-       if (copy_from_user(buf, userbuf, size))
-               return -EFAULT;
-
-       if (sscanf(buf, "%u", &opt) != 1) {
-               printk(KERN_ERR "%s: sscanf input error\n", sdata->dev->name);
-               return -EINVAL;
-       }
-       switch (opt) {
-       case 1:
-               ieee80211_send_dls_req(sdata->dev, &sdata->u.sta,
-                                      sdata->u.sta.dls_mac, 0);
-               break;
-       case 2:
-               ieee80211_send_dls_teardown(sdata->dev, &sdata->u.sta,
-                                           sdata->u.sta.dls_mac,
-                                           WLAN_REASON_QSTA_NOT_USE);
-               break;
-       default:
-               printk(KERN_ERR "Unknown DLS Operation: %d\n", opt);
-               break;
-       }
-       return count;
-}
-
-static const struct file_operations qos_dls_op_ops = {
-       .read = qos_dls_op_read,
-       .write = qos_dls_op_write,
-       .open = mac80211_open_file_generic,
-};
-
-#define DEBUGFS_TSINFO_FILE(_name, min_val, max_val)                   \
-static ssize_t tsinfo_ ##_name## _read(struct file *file,              \
-                                      char __user *userbuf,            \
-                                      size_t count, loff_t *ppos)      \
-{                                                                      \
-       char buf[20];                                                   \
-       struct ieee80211_sub_if_data *sdata = file->private_data;       \
-       int res = scnprintf(buf, count, "%u\n",                         \
-               IEEE80211_TSINFO_## _name (sdata->u.sta.tspec.ts_info));\
-       return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
-}                                                                      \
-                                                                       \
-static ssize_t tsinfo_ ##_name## _write(struct file *file,             \
-                                       const char __user *userbuf,     \
-                                       size_t count, loff_t *ppos)     \
-{                                                                      \
-       char buf[20];                                                   \
-       size_t size;                                                    \
-       int val;                                                        \
-       struct ieee80211_sub_if_data *sdata = file->private_data;       \
-                                                                       \
-       size = min(sizeof(buf) - 1, count);                             \
-       buf[size] = '\0';                                               \
-       if (copy_from_user(buf, userbuf, size))                         \
-               return -EFAULT;                                         \
-                                                                       \
-       val = simple_strtoul(buf, NULL, 0);                             \
-       if ((val < min_val) || (val > max_val)) {                       \
-               printk(KERN_ERR "%s: set value (%u) out of range "      \
-                      "[%u, %u]\n",sdata->dev->name,val,min_val,max_val);\
-               return -EINVAL;                                         \
-       }                                                               \
-       IEEE80211_SET_TSINFO_ ##_name (sdata->u.sta.tspec.ts_info, val);\
-       return count;                                                   \
-}                                                                      \
-                                                                       \
-static const struct file_operations tsinfo_ ##_name## _ops = {         \
-       .read = tsinfo_ ##_name## _read,                                \
-       .write = tsinfo_ ##_name## _write,                              \
-       .open = mac80211_open_file_generic,                             \
-};
-
-#define DEBUGFS_TSINFO_ADD_TSID                                                \
-       sdata->debugfs.sta.tsinfo.tsid =                                \
-               debugfs_create_file("tsid", 0444, tsinfod,              \
-                                   sdata, &tsinfo_TSID_ops);
-
-#define DEBUGFS_TSINFO_ADD_DIR                                         \
-       sdata->debugfs.sta.tsinfo.direction =                           \
-               debugfs_create_file("direction", 0444, tsinfod,         \
-                                   sdata, &tsinfo_DIR_ops);
-
-#define DEBUGFS_TSINFO_ADD_UP                                          \
-       sdata->debugfs.sta.tsinfo.up =                                  \
-               debugfs_create_file("up", 0444, tsinfod,                \
-                                   sdata, &tsinfo_UP_ops);
-
-#define DEBUGFS_TSINFO_DEL(name)                                       \
-       do {                                                            \
-               debugfs_remove(sdata->debugfs.sta.tsinfo.name);         \
-               sdata->debugfs.sta.tsinfo.name = NULL;                  \
-       } while (0)
-
-DEBUGFS_TSINFO_FILE(TSID, 8, 15);
-DEBUGFS_TSINFO_FILE(DIR, 0, 3);
-DEBUGFS_TSINFO_FILE(UP, 0, 7);
-
-#define DEBUGFS_TSPEC_FILE(name, format_string, endian_f1, endian_f2)  \
-static ssize_t tspec_ ##name## _read(struct file *file,                        \
-                                     char __user *userbuf,             \
-                                     size_t count, loff_t *ppos)       \
-{                                                                      \
-       char buf[20];                                                   \
-       struct ieee80211_sub_if_data *sdata = file->private_data;       \
-       int res = scnprintf(buf, count, format_string "\n",             \
-                           endian_f1(sdata->u.sta.tspec.name));        \
-       return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
-}                                                                      \
-                                                                       \
-static ssize_t tspec_ ##name## _write(struct file *file,               \
-                                      const char __user *userbuf,      \
-                                      size_t count, loff_t *ppos)      \
-{                                                                      \
-       char buf[20];                                                   \
-       size_t size;                                                    \
-       struct ieee80211_sub_if_data *sdata = file->private_data;       \
-                                                                       \
-       size = min(sizeof(buf) - 1, count);                             \
-       buf[size] = '\0';                                               \
-       if (copy_from_user(buf, userbuf, size))                         \
-               return -EFAULT;                                         \
-                                                                       \
-       sdata->u.sta.tspec.name = endian_f2(simple_strtoul(buf, NULL, 0));\
-       return count;                                                   \
-}                                                                      \
-                                                                       \
-static const struct file_operations tspec_ ##name## _ops = {           \
-       .read = tspec_ ##name## _read,                                  \
-       .write = tspec_ ##name## _write,                                \
-       .open = mac80211_open_file_generic,                             \
-};
-
-#define DEBUGFS_TSPEC_ADD(name)                                                \
-       sdata->debugfs.sta.tspec.name = debugfs_create_file(#name,      \
-               0444, tspecd, sdata, &tspec_ ##name## _ops);
-
-#define DEBUGFS_TSPEC_DEL(name)                                                \
-       do {                                                            \
-               debugfs_remove(sdata->debugfs.sta.tspec.name);          \
-               sdata->debugfs.sta.tspec.name = NULL;                   \
-       } while (0)
-
-DEBUGFS_TSPEC_FILE(nominal_msdu_size, "%hu", le16_to_cpu, cpu_to_le16);
-DEBUGFS_TSPEC_FILE(max_msdu_size, "%hu", le16_to_cpu, cpu_to_le16);
-DEBUGFS_TSPEC_FILE(min_service_interval, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(max_service_interval, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(inactivity_interval, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(suspension_interval, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(service_start_time, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(min_data_rate, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(mean_data_rate, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(peak_data_rate, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(burst_size, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(delay_bound, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(min_phy_rate, "%u", le32_to_cpu, cpu_to_le32);
-DEBUGFS_TSPEC_FILE(surplus_band_allow, "%hu", le16_to_cpu, cpu_to_le16);
-DEBUGFS_TSPEC_FILE(medium_time, "%hu", le16_to_cpu, cpu_to_le16);
-
-
 /* common attributes */
 IEEE80211_IF_FILE(channel_use, channel_use, DEC);
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
@@ -373,13 +112,13 @@ static ssize_t ieee80211_if_fmt_flags(
        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 {
        return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
-                        sdata->u.sta.ssid_set ? "SSID\n" : "",
-                        sdata->u.sta.bssid_set ? "BSSID\n" : "",
-                        sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "",
-                        sdata->u.sta.authenticated ? "AUTH\n" : "",
-                        sdata->u.sta.associated ? "ASSOC\n" : "",
-                        sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "",
-                        sdata->u.sta.use_protection ? "CTS prot\n" : "");
+                sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
+                sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : "");
 }
 __IEEE80211_IF_FILE(flags);
 
@@ -422,33 +161,12 @@ __IEEE80211_IF_FILE(beacon_tail_len);
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
-/* VLAN attributes */
-IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
-
-/* MONITOR attributes */
-static ssize_t ieee80211_if_fmt_mode(
-       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-       struct ieee80211_local *local = sdata->local;
-
-       return scnprintf(buf, buflen, "%s\n",
-                        ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
-                         local->open_count == local->monitors) ?
-                        "hard" : "soft");
-}
-__IEEE80211_IF_FILE(mode);
-
-
 #define DEBUGFS_ADD(name, type)\
        sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
                sdata->debugfsdir, sdata, &name##_ops);
 
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
-       struct dentry *qosd;
-       struct dentry *tsinfod;
-       struct dentry *tspecd;
-
        DEBUGFS_ADD(channel_use, sta);
        DEBUGFS_ADD(drop_unencrypted, sta);
        DEBUGFS_ADD(eapol, sta);
@@ -467,42 +185,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(auth_alg, sta);
        DEBUGFS_ADD(auth_transaction, sta);
        DEBUGFS_ADD(flags, sta);
-
-       qosd = debugfs_create_dir("qos", sdata->debugfsdir);
-       sdata->debugfs.sta.qos_dir = qosd;
-
-       DEBUGFS_QOS_ADD(addts_11e);
-       DEBUGFS_QOS_ADD(addts_wmm);
-       DEBUGFS_QOS_ADD(delts_11e);
-       DEBUGFS_QOS_ADD(delts_wmm);
-       DEBUGFS_QOS_ADD(dls_mac);
-       DEBUGFS_QOS_ADD(dls_op);
-
-       tsinfod = debugfs_create_dir("ts_info", qosd);
-       sdata->debugfs.sta.tsinfo_dir = tsinfod;
-
-       DEBUGFS_TSINFO_ADD_TSID;
-       DEBUGFS_TSINFO_ADD_DIR;
-       DEBUGFS_TSINFO_ADD_UP;
-
-       tspecd = debugfs_create_dir("tspec", qosd);
-       sdata->debugfs.sta.tspec_dir = tspecd;
-
-       DEBUGFS_TSPEC_ADD(nominal_msdu_size);
-       DEBUGFS_TSPEC_ADD(max_msdu_size);
-       DEBUGFS_TSPEC_ADD(min_service_interval);
-       DEBUGFS_TSPEC_ADD(max_service_interval);
-       DEBUGFS_TSPEC_ADD(inactivity_interval);
-       DEBUGFS_TSPEC_ADD(suspension_interval);
-       DEBUGFS_TSPEC_ADD(service_start_time);
-       DEBUGFS_TSPEC_ADD(min_data_rate);
-       DEBUGFS_TSPEC_ADD(mean_data_rate);
-       DEBUGFS_TSPEC_ADD(peak_data_rate);
-       DEBUGFS_TSPEC_ADD(burst_size);
-       DEBUGFS_TSPEC_ADD(delay_bound);
-       DEBUGFS_TSPEC_ADD(min_phy_rate);
-       DEBUGFS_TSPEC_ADD(surplus_band_allow);
-       DEBUGFS_TSPEC_ADD(medium_time);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -537,12 +219,10 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(drop_unencrypted, vlan);
        DEBUGFS_ADD(eapol, vlan);
        DEBUGFS_ADD(ieee8021_x, vlan);
-       DEBUGFS_ADD(vlan_id, vlan);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(mode, monitor);
 }
 
 static void add_files(struct ieee80211_sub_if_data *sdata)
@@ -598,40 +278,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_DEL(auth_alg, sta);
        DEBUGFS_DEL(auth_transaction, sta);
        DEBUGFS_DEL(flags, sta);
-
-       DEBUGFS_TSINFO_DEL(tsid);
-       DEBUGFS_TSINFO_DEL(direction);
-       DEBUGFS_TSINFO_DEL(up);
-
-       DEBUGFS_TSPEC_DEL(nominal_msdu_size);
-       DEBUGFS_TSPEC_DEL(max_msdu_size);
-       DEBUGFS_TSPEC_DEL(min_service_interval);
-       DEBUGFS_TSPEC_DEL(max_service_interval);
-       DEBUGFS_TSPEC_DEL(inactivity_interval);
-       DEBUGFS_TSPEC_DEL(suspension_interval);
-       DEBUGFS_TSPEC_DEL(service_start_time);
-       DEBUGFS_TSPEC_DEL(min_data_rate);
-       DEBUGFS_TSPEC_DEL(mean_data_rate);
-       DEBUGFS_TSPEC_DEL(peak_data_rate);
-       DEBUGFS_TSPEC_DEL(burst_size);
-       DEBUGFS_TSPEC_DEL(delay_bound);
-       DEBUGFS_TSPEC_DEL(min_phy_rate);
-       DEBUGFS_TSPEC_DEL(surplus_band_allow);
-       DEBUGFS_TSPEC_DEL(medium_time);
-
-       DEBUGFS_QOS_DEL(addts_11e);
-       DEBUGFS_QOS_DEL(addts_wmm);
-       DEBUGFS_QOS_DEL(delts_11e);
-       DEBUGFS_QOS_DEL(delts_wmm);
-       DEBUGFS_QOS_DEL(dls_mac);
-       DEBUGFS_QOS_DEL(dls_op);
-
-       debugfs_remove(sdata->debugfs.sta.tspec_dir);
-       sdata->debugfs.sta.tspec_dir = NULL;
-       debugfs_remove(sdata->debugfs.sta.tsinfo_dir);
-       sdata->debugfs.sta.tsinfo_dir = NULL;
-       debugfs_remove(sdata->debugfs.sta.qos_dir);
-       sdata->debugfs.sta.qos_dir = NULL;
 }
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -666,12 +312,10 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_DEL(drop_unencrypted, vlan);
        DEBUGFS_DEL(eapol, vlan);
        DEBUGFS_DEL(ieee8021_x, vlan);
-       DEBUGFS_DEL(vlan_id, vlan);
 }
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(mode, monitor);
 }
 
 static void del_files(struct ieee80211_sub_if_data *sdata, int type)
@@ -734,9 +378,9 @@ static int netdev_notify(struct notifier_block * nb,
                         void *ndev)
 {
        struct net_device *dev = ndev;
-       /* TODO
+       struct dentry *dir;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        char buf[10+IFNAMSIZ];
-       */
 
        if (state != NETDEV_CHANGENAME)
                return 0;
@@ -747,10 +391,11 @@ static int netdev_notify(struct notifier_block * nb,
        if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
                return 0;
 
-       /* TODO
        sprintf(buf, "netdev:%s", dev->name);
-       debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf);
-       */
+       dir = sdata->debugfsdir;
+       if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
+               printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
+                      "dir to %s\n", buf);
 
        return 0;
 }
index 6cfe35a9949b57bcf3a37c99d621958acfbbb074..4ea0ea7ea040421583c6193553995359f46aa66e 100644 (file)
@@ -60,9 +60,7 @@ static const struct file_operations sta_ ##name## _ops = {            \
                STA_OPS(name)
 
 STA_FILE(aid, aid, D);
-STA_FILE(key_idx_compression, key_idx_compression, D);
 STA_FILE(dev, dev->name, S);
-STA_FILE(vlan_id, vlan_id, D);
 STA_FILE(rx_packets, rx_packets, LU);
 STA_FILE(tx_packets, tx_packets, LU);
 STA_FILE(rx_bytes, rx_bytes, LU);
@@ -87,7 +85,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
 {
        char buf[100];
        struct sta_info *sta = file->private_data;
-       int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s",
+       int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
                sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
                sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
                sta->flags & WLAN_STA_PS ? "PS\n" : "",
@@ -96,7 +94,6 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
                sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
                sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
                sta->flags & WLAN_STA_WME ? "WME\n" : "",
-               sta->flags & WLAN_STA_HT ? "HT\n" : "",
                sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
diff --git a/package/mac80211/src/mac80211/event.c b/package/mac80211/src/mac80211/event.c
new file mode 100644 (file)
index 0000000..68a526c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * mac80211 - events
+ */
+
+#include <linux/netdevice.h>
+#include <net/iw_handler.h>
+#include "ieee80211_i.h"
+
+/*
+ * indicate a failed Michael MIC to userspace; the passed packet
+ * (in the variable hdr) must be long enough to extract the TKIP
+ * fields like TSC
+ */
+void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
+                                    struct ieee80211_hdr *hdr)
+{
+       union iwreq_data wrqu;
+       char *buf = kmalloc(128, GFP_ATOMIC);
+
+       if (buf) {
+               /* TODO: needed parameters: count, key type, TSC */
+               sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+                       "keyid=%d %scast addr=" MAC_FMT ")",
+                       keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+                       MAC_ARG(hdr->addr2));
+               memset(&wrqu, 0, sizeof(wrqu));
+               wrqu.data.length = strlen(buf);
+               wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+               kfree(buf);
+       }
+
+       /*
+        * TODO: re-add support for sending MIC failure indication
+        * with all info via nl80211
+        */
+}
diff --git a/package/mac80211/src/mac80211/hostapd_ioctl.h b/package/mac80211/src/mac80211/hostapd_ioctl.h
deleted file mode 100644 (file)
index e35233c..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver
- * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- * Copyright 2002-2004, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef HOSTAPD_IOCTL_H
-#define HOSTAPD_IOCTL_H
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#endif /* __KERNEL__ */
-
-#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
-
-/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes:
- * This table is no longer added to, the whole sub-ioctl
- * mess shall be deleted completely. */
-enum {
-       PRISM2_PARAM_BEACON_INT = 3,
-       PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
-       PRISM2_PARAM_DTIM_PERIOD = 11,
-       PRISM2_PARAM_AP_AUTH_ALGS = 15,
-       PRISM2_PARAM_HOST_ENCRYPT = 17,
-       PRISM2_PARAM_HOST_DECRYPT = 18,
-       PRISM2_PARAM_IEEE_802_1X = 23,
-       PRISM2_PARAM_ANTSEL_TX = 24,
-       PRISM2_PARAM_ANTSEL_RX = 25,
-
-       /* Instant802 additions */
-       PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
-       PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
-       PRISM2_PARAM_PREAMBLE = 1003,
-       PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
-       PRISM2_PARAM_NEXT_MODE = 1008,
-       PRISM2_PARAM_CLEAR_KEYS = 1009,
-       PRISM2_PARAM_RADIO_ENABLED = 1010,
-       PRISM2_PARAM_ANTENNA_MODE = 1013,
-       PRISM2_PARAM_PRIVACY_INVOKED = 1014,
-       PRISM2_PARAM_BROADCAST_SSID = 1015,
-       PRISM2_PARAM_STAT_TIME = 1016,
-       PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
-       PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
-       PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
-       PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
-       PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
-       PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
-       PRISM2_PARAM_EAPOL = 1023,
-       PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
-       PRISM2_PARAM_KEY_INDEX = 1025,
-       PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
-       PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033,
-       PRISM2_PARAM_ALLOW_BROADCAST_ALWAYS = 1034,
-       PRISM2_PARAM_SCAN_FLAGS = 1035,
-       PRISM2_PARAM_HW_MODES = 1036,
-       PRISM2_PARAM_CREATE_IBSS = 1037,
-       PRISM2_PARAM_WMM_ENABLED = 1038,
-       PRISM2_PARAM_MIXED_CELL = 1039,
-       PRISM2_PARAM_KEY_MGMT = 1040,
-       PRISM2_PARAM_RADAR_DETECT = 1043,
-       PRISM2_PARAM_SPECTRUM_MGMT = 1044,
-       PRISM2_PARAM_USER_SPACE_MLME = 1045,
-       PRISM2_PARAM_MGMT_IF = 1046,
-};
-
-/* PRISM2_IOCTL_HOSTAPD ioctl() cmd:
- * This table is no longer added to, the hostapd ioctl
- * shall be deleted completely. */
-enum {
-       PRISM2_HOSTAPD_FLUSH = 1,
-       PRISM2_HOSTAPD_ADD_STA = 2,
-       PRISM2_HOSTAPD_REMOVE_STA = 3,
-       PRISM2_HOSTAPD_GET_INFO_STA = 4,
-       PRISM2_SET_ENCRYPTION = 6,
-       PRISM2_GET_ENCRYPTION = 7,
-       PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
-       PRISM2_HOSTAPD_MLME = 13,
-
-       /* Instant802 additions */
-       PRISM2_HOSTAPD_SET_BEACON = 1001,
-       PRISM2_HOSTAPD_GET_HW_FEATURES = 1002,
-       PRISM2_HOSTAPD_WPA_TRIGGER = 1004,
-       PRISM2_HOSTAPD_SET_RATE_SETS = 1005,
-       PRISM2_HOSTAPD_ADD_IF = 1006,
-       PRISM2_HOSTAPD_REMOVE_IF = 1007,
-       PRISM2_HOSTAPD_GET_DOT11COUNTERSTABLE = 1008,
-       PRISM2_HOSTAPD_GET_LOAD_STATS = 1009,
-       PRISM2_HOSTAPD_SET_STA_VLAN = 1010,
-       PRISM2_HOSTAPD_SET_GENERIC_INFO_ELEM = 1011,
-       PRISM2_HOSTAPD_SET_CHANNEL_FLAG = 1012,
-       PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN = 1013,
-       PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS = 1014,
-       PRISM2_HOSTAPD_GET_TX_STATS = 1016,
-       PRISM2_HOSTAPD_UPDATE_IF = 1017,
-       PRISM2_HOSTAPD_SCAN_REQ = 1019,
-       PRISM2_STA_GET_STATE = 1020,
-       PRISM2_HOSTAPD_FLUSH_IFS = 1021,
-       PRISM2_HOSTAPD_SET_RADAR_PARAMS = 1023,
-       PRISM2_HOSTAPD_SET_QUIET_PARAMS = 1024,
-};
-
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
-#define HOSTAP_CRYPT_ALG_NAME_LEN 16
-
-#ifndef ALIGNED
-#define ALIGNED __attribute__ ((aligned))
-#endif
-
-struct prism2_hostapd_param {
-       u32 cmd;
-       u8 sta_addr[ETH_ALEN];
-       u8 pad[2];
-       union {
-               struct {
-                       u16 aid;
-                       u16 capability;
-                       u8 supp_rates[32];
-                       u8 wds_flags;
-#define IEEE80211_STA_DYNAMIC_ENC BIT(0)
-                       u8 enc_flags;
-                       u16 listen_interval;
-               } add_sta;
-               struct {
-                       u32 inactive_msec;
-                       u32 rx_packets;
-                       u32 tx_packets;
-                       u32 rx_bytes;
-                       u32 tx_bytes;
-                       u32 current_tx_rate; /* in 100 kbps */
-                       u32 channel_use;
-                       u32 flags;
-                       u32 num_ps_buf_frames;
-                       u32 tx_retry_failed;
-                       u32 tx_retry_count;
-                       u32 last_rssi;
-                       u32 last_ack_rssi;
-               } get_info_sta;
-               struct {
-                       char alg[HOSTAP_CRYPT_ALG_NAME_LEN];
-                       u32 flags;
-                       u32 err;
-                       u8 idx;
-#define HOSTAP_SEQ_COUNTER_SIZE 8
-                       u8 seq_counter[HOSTAP_SEQ_COUNTER_SIZE];
-                       u16 key_len;
-                       u8 key[0] ALIGNED;
-               } crypt;
-               struct {
-                       u32 flags_and;
-                       u32 flags_or;
-               } set_flags_sta;
-               struct {
-                       u16 head_len;
-                       u16 tail_len;
-                       u8 data[0] ALIGNED; /* head_len + tail_len bytes */
-               } beacon;
-               struct {
-                       u16 num_modes;
-                       u16 flags;
-                       u8 data[0] ALIGNED; /* num_modes * feature data */
-               } hw_features;
-               struct {
-                       u8  now;
-                       s8  our_mode_only;
-                       s16 last_rx;
-                       u16 channel;
-                       s16 interval; /* seconds */
-                       s32 listen;   /* microseconds */
-               } scan;
-               struct {
-#define WPA_TRIGGER_FAIL_TX_MIC BIT(0)
-#define WPA_TRIGGER_FAIL_TX_ICV BIT(1)
-#define WPA_TRIGGER_FAIL_RX_MIC BIT(2)
-#define WPA_TRIGGER_FAIL_RX_ICV BIT(3)
-#define WPA_TRIGGER_TX_REPLAY BIT(4)
-#define WPA_TRIGGER_TX_REPLAY_FRAG BIT(5)
-#define WPA_TRIGGER_TX_SKIP_SEQ BIT(6)
-                       u32 trigger;
-               } wpa_trigger;
-               struct {
-                       u16 mode; /* MODE_* */
-                       u16 num_supported_rates;
-                       u16 num_basic_rates;
-                       u8 data[0] ALIGNED; /* num_supported_rates * u16 +
-                                            * num_basic_rates * u16 */
-               } set_rate_sets;
-               struct {
-                       u8 type; /* WDS, VLAN, etc */
-                       u8 name[IFNAMSIZ];
-                       u8 data[0] ALIGNED;
-               } if_info;
-               struct dot11_counters {
-                       u32 dot11TransmittedFragmentCount;
-                       u32 dot11MulticastTransmittedFrameCount;
-                       u32 dot11FailedCount;
-                       u32 dot11ReceivedFragmentCount;
-                       u32 dot11MulticastReceivedFrameCount;
-                       u32 dot11FCSErrorCount;
-                       u32 dot11TransmittedFrameCount;
-                       u32 dot11WEPUndecryptableCount;
-                       u32 dot11ACKFailureCount;
-                       u32 dot11RTSFailureCount;
-                       u32 dot11RTSSuccessCount;
-               } dot11CountersTable;
-               struct {
-#define LOAD_STATS_CLEAR BIT(1)
-                       u32 flags;
-                       u32 channel_use;
-               } get_load_stats;
-               struct {
-                       char vlan_name[IFNAMSIZ];
-                       int vlan_id;
-               } set_sta_vlan;
-               struct {
-                       u8 len;
-                       u8 data[0] ALIGNED;
-               } set_generic_info_elem;
-               struct {
-                       u16 mode; /* MODE_* */
-                       u16 chan;
-                       u32 flag;
-                       u8 power_level; /* regulatory limit in dBm */
-                       u8 antenna_max;
-               } set_channel_flag;
-               struct {
-                       u32 rd;
-               } set_regulatory_domain;
-               struct {
-                       u32 queue;
-                       s32 aifs;
-                       u32 cw_min;
-                       u32 cw_max;
-                       u32 burst_time; /* maximum burst time in 0.1 ms, i.e.,
-                                        * 10 = 1 ms */
-               } tx_queue_params;
-               struct ieee80211_tx_stats {
-                       struct {
-                               unsigned int len; /* num packets in queue */
-                               unsigned int limit; /* queue len (soft) limit
-                                                    */
-                               unsigned int count; /* total num frames sent */
-                       } data[4];
-               } get_tx_stats;
-               struct {
-                       u8 ssid_len;
-                       u8 ssid[0] ALIGNED;
-               } scan_req;
-               struct {
-                       u32 state;
-               } sta_get_state;
-               struct {
-#define MLME_STA_DEAUTH 0
-#define MLME_STA_DISASSOC 1
-                       u16 cmd;
-                       u16 reason_code;
-               } mlme;
-               struct {
-                       u8 radar_firpwr_threshold;
-                       u8 radar_rssi_threshold;
-                       u8 pulse_height_threshold;
-                       u8 pulse_rssi_threshold;
-                       u8 pulse_inband_threshold;
-               } radar;
-               struct {
-                       unsigned int period;
-                       unsigned int offset;
-                       unsigned int duration;
-               } quiet;
-               struct {
-                       u8 dummy[80]; /* Make sizeof() this struct large enough
-                                      * with some compiler versions. */
-               } dummy;
-       } u;
-};
-
-#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
-#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
-
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
-#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
-#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
-#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
-#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
-
-#define HOSTAP_HW_FLAG_NULLFUNC_OK BIT(0)
-
-enum {
-       IEEE80211_KEY_MGMT_NONE = 0,
-       IEEE80211_KEY_MGMT_IEEE8021X = 1,
-       IEEE80211_KEY_MGMT_WPA_PSK = 2,
-       IEEE80211_KEY_MGMT_WPA_EAP = 3,
-};
-
-
-/* Data structures used for get_hw_features ioctl */
-struct hostapd_ioctl_hw_modes_hdr {
-       int mode;
-       int num_channels;
-       int num_rates;
-};
-
-struct ieee80211_channel_data {
-       short chan; /* channel number (IEEE 802.11) */
-       short freq; /* frequency in MHz */
-       int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
-};
-
-struct ieee80211_rate_data {
-       int rate; /* rate in 100 kbps */
-       int flags; /* IEEE80211_RATE_ flags */
-};
-
-
-/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */
-enum {
-       HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3,
-       HOSTAP_IF_STA = 4
-};
-
-struct hostapd_if_wds {
-       u8 remote_addr[ETH_ALEN];
-};
-
-struct hostapd_if_vlan {
-       u8 id;
-};
-
-struct hostapd_if_bss {
-       u8 bssid[ETH_ALEN];
-};
-
-struct hostapd_if_sta {
-};
-
-#endif /* HOSTAPD_IOCTL_H */
index 5202c487ac5d9c5276b04b6893cc4f7f0f6c1eb0..64fa7204b447ae2de8928af6b2c3f726ddf79f3d 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/rtnetlink.h>
-#include <net/iw_handler.h>
-#include <linux/compiler.h>
 #include <linux/bitmap.h>
 #include <net/cfg80211.h>
 
-#include "ieee80211_common.h"
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "wep.h"
-#include "wpa.h"
-#include "tkip.h"
 #include "wme.h"
 #include "aes_ccm.h"
 #include "ieee80211_led.h"
-#include "ieee80211_cfg.h"
+#include "cfg.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
-#include "debugfs_key.h"
 
-/* privid for wiphys to determine whether they belong to us or not */
-void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static const unsigned char rfc1042_header[] =
-       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static const unsigned char bridge_tunnel_header[] =
-       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-
-/* No encapsulation header if EtherType < 0x600 (=length) */
-static const unsigned char eapol_header[] =
-       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
-
-
-static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
-                                             struct ieee80211_hdr *hdr)
-{
-       /* Set the sequence number for this frame. */
-       hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
+/*
+ * For seeing transmitted packets on monitor interfaces
+ * we have a radiotap header too.
+ */
+struct ieee80211_tx_status_rtap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       __le16 tx_flags;
+       u8 data_retries;
+} __attribute__ ((packed));
 
-       /* Increase the sequence number. */
-       sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
-}
+/* common interface routines */
 
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-                       const struct ieee80211_key *data)
+static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
 {
-       struct ieee80211_key_conf *conf;
-
-       conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
-       if (!conf)
-               return NULL;
-
-       conf->hw_key_idx = data->hw_key_idx;
-       conf->alg = data->alg;
-       conf->keylen = data->keylen;
-       conf->flags = 0;
-       if (data->force_sw_encrypt)
-               conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
-       conf->keyidx = data->keyidx;
-       if (data->default_tx_key)
-               conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
-       if (local->default_wep_only)
-               conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
-       memcpy(conf->key, data->key, data->keylen);
-
-       return conf;
+       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+       return ETH_ALEN;
 }
 
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-                                         int idx, size_t key_len, gfp_t flags)
+/* must be called under mdev tx lock */
+static void ieee80211_configure_filter(struct ieee80211_local *local)
 {
-       struct ieee80211_key *key;
+       unsigned int changed_flags;
+       unsigned int new_flags = 0;
 
-       key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
-       if (!key)
-               return NULL;
-       kref_init(&key->kref);
-       return key;
-}
+       if (atomic_read(&local->iff_promiscs))
+               new_flags |= FIF_PROMISC_IN_BSS;
 
-static void ieee80211_key_release(struct kref *kref)
-{
-       struct ieee80211_key *key;
+       if (atomic_read(&local->iff_allmultis))
+               new_flags |= FIF_ALLMULTI;
 
-       key = container_of(kref, struct ieee80211_key, kref);
-       if (key->alg == ALG_CCMP)
-               ieee80211_aes_key_free(key->u.ccmp.tfm);
-       ieee80211_debugfs_key_remove(key);
-       kfree(key);
-}
+       if (local->monitors)
+               new_flags |= FIF_CONTROL |
+                            FIF_OTHER_BSS |
+                            FIF_BCN_PRBRESP_PROMISC;
 
-void ieee80211_key_free(struct ieee80211_key *key)
-{
-       if (key)
-               kref_put(&key->kref, ieee80211_key_release);
-}
+       changed_flags = local->filter_flags ^ new_flags;
 
-static int rate_list_match(const int *rate_list, int rate)
-{
-       int i;
+       /* be a bit nasty */
+       new_flags |= (1<<31);
 
-       if (!rate_list)
-               return 0;
+       local->ops->configure_filter(local_to_hw(local),
+                                    changed_flags, &new_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
 
-       for (i = 0; rate_list[i] >= 0; i++)
-               if (rate_list[i] == rate)
-                       return 1;
+       WARN_ON(new_flags & (1<<31));
 
-       return 0;
+       local->filter_flags = new_flags & ~(1<<31);
 }
 
+/* master interface */
 
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-                            struct ieee80211_hw_mode *mode)
+static int ieee80211_master_open(struct net_device *dev)
 {
-       int i;
-
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-
-               rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
-                                IEEE80211_RATE_BASIC);
-
-               if (local->supp_rates[mode->mode]) {
-                       if (!rate_list_match(local->supp_rates[mode->mode],
-                                            rate->rate))
-                               continue;
-               }
-
-               rate->flags |= IEEE80211_RATE_SUPPORTED;
-
-               /* Use configured basic rate set if it is available. If not,
-                * use defaults that are sane for most cases. */
-               if (local->basic_rates[mode->mode]) {
-                       if (rate_list_match(local->basic_rates[mode->mode],
-                                           rate->rate))
-                               rate->flags |= IEEE80211_RATE_BASIC;
-               } else switch (mode->mode) {
-               case MODE_IEEE80211A:
-                       if (rate->rate == 60 || rate->rate == 120 ||
-                           rate->rate == 240)
-                               rate->flags |= IEEE80211_RATE_BASIC;
-                       break;
-               case MODE_IEEE80211B:
-                       if (rate->rate == 10 || rate->rate == 20)
-                               rate->flags |= IEEE80211_RATE_BASIC;
-                       break;
-               case MODE_ATHEROS_TURBO:
-                       if (rate->rate == 120 || rate->rate == 240 ||
-                           rate->rate == 480)
-                               rate->flags |= IEEE80211_RATE_BASIC;
-                       break;
-               case MODE_IEEE80211G:
-                       if (rate->rate == 10 || rate->rate == 20 ||
-                           rate->rate == 55 || rate->rate == 110)
-                               rate->flags |= IEEE80211_RATE_BASIC;
-                       break;
-               }
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata;
+       int res = -EOPNOTSUPP;
 
-               /* Set ERP and MANDATORY flags based on phymode */
-               switch (mode->mode) {
-               case MODE_IEEE80211A:
-                       if (rate->rate == 60 || rate->rate == 120 ||
-                           rate->rate == 240)
-                               rate->flags |= IEEE80211_RATE_MANDATORY;
-                       break;
-               case MODE_IEEE80211B:
-                       if (rate->rate == 10)
-                               rate->flags |= IEEE80211_RATE_MANDATORY;
-                       break;
-               case MODE_ATHEROS_TURBO:
-                       break;
-               case MODE_IEEE80211G:
-                       if (rate->rate == 10 || rate->rate == 20 ||
-                           rate->rate == 55 || rate->rate == 110 ||
-                           rate->rate == 60 || rate->rate == 120 ||
-                           rate->rate == 240)
-                               rate->flags |= IEEE80211_RATE_MANDATORY;
+       /* we hold the RTNL here so can safely walk the list */
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->dev != dev && netif_running(sdata->dev)) {
+                       res = 0;
                        break;
                }
-               if (ieee80211_is_erp_rate(mode->mode, rate->rate))
-                       rate->flags |= IEEE80211_RATE_ERP;
        }
+       return res;
 }
 
-
-static void ieee80211_key_threshold_notify(struct net_device *dev,
-                                          struct ieee80211_key *key,
-                                          struct sta_info *sta)
+static int ieee80211_master_stop(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sk_buff *skb;
-       struct ieee80211_msg_key_notification *msg;
-
-       /* if no one will get it anyway, don't even allocate it.
-        * unlikely because this is only relevant for APs
-        * where the device must be open... */
-       if (unlikely(!local->apdev))
-               return;
-
-       skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
-                           sizeof(struct ieee80211_msg_key_notification));
-       if (!skb)
-               return;
-
-       skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-       msg = (struct ieee80211_msg_key_notification *)
-               skb_put(skb, sizeof(struct ieee80211_msg_key_notification));
-       msg->tx_rx_count = key->tx_rx_count;
-       memcpy(msg->ifname, dev->name, IFNAMSIZ);
-       if (sta)
-               memcpy(msg->addr, sta->addr, ETH_ALEN);
-       else
-               memset(msg->addr, 0xff, ETH_ALEN);
-
-       key->tx_rx_count = 0;
-
-       ieee80211_rx_mgmt(local, skb, NULL,
-                         ieee80211_msg_key_threshold_notification);
-}
-
-
-static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
-{
-       u16 fc;
-
-       if (len < 24)
-               return NULL;
-
-       fc = le16_to_cpu(hdr->frame_control);
-
-       switch (fc & IEEE80211_FCTL_FTYPE) {
-       case IEEE80211_FTYPE_DATA:
-               switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-               case IEEE80211_FCTL_TODS:
-                       return hdr->addr1;
-               case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-                       return NULL;
-               case IEEE80211_FCTL_FROMDS:
-                       return hdr->addr2;
-               case 0:
-                       return hdr->addr3;
-               }
-               break;
-       case IEEE80211_FTYPE_MGMT:
-               return hdr->addr3;
-       case IEEE80211_FTYPE_CTL:
-               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
-                       return hdr->addr1;
-               else
-                       return NULL;
-       }
-
-       return NULL;
-}
-
-int ieee80211_get_hdrlen(u16 fc)
-{
-       int hdrlen = 24;
+       struct ieee80211_sub_if_data *sdata;
 
-       switch (fc & IEEE80211_FCTL_FTYPE) {
-       case IEEE80211_FTYPE_DATA:
-               if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
-                       hdrlen = 30; /* Addr4 */
-               /*
-                * The QoS Control field is two bytes and its presence is
-                * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
-                * hdrlen if that bit is set.
-                * This works by masking out the bit and shifting it to
-                * bit position 1 so the result has the value 0 or 2.
-                */
-               hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
-                               >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
-               break;
-       case IEEE80211_FTYPE_CTL:
-               /*
-                * ACK and CTS are 10 bytes, all others 16. To see how
-                * to get this condition consider
-                *   subtype mask:   0b0000000011110000 (0x00F0)
-                *   ACK subtype:    0b0000000011010000 (0x00D0)
-                *   CTS subtype:    0b0000000011000000 (0x00C0)
-                *   bits that matter:         ^^^      (0x00E0)
-                *   value of those: 0b0000000011000000 (0x00C0)
-                */
-               if ((fc & 0xE0) == 0xC0)
-                       hdrlen = 10;
-               else
-                       hdrlen = 16;
-               break;
-       }
+       /* we hold the RTNL here so can safely walk the list */
+       list_for_each_entry(sdata, &local->interfaces, list)
+               if (sdata->dev != dev && netif_running(sdata->dev))
+                       dev_close(sdata->dev);
 
-       return hdrlen;
+       return 0;
 }
-EXPORT_SYMBOL(ieee80211_get_hdrlen);
 
-int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+static void ieee80211_master_set_multicast_list(struct net_device *dev)
 {
-       const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
-       int hdrlen;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (unlikely(skb->len < 10))
-               return 0;
-       hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
-       if (unlikely(hdrlen > skb->len))
-               return 0;
-       return hdrlen;
+       ieee80211_configure_filter(local);
 }
-EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-
-static int ieee80211_get_radiotap_len(struct sk_buff *skb)
-{
-       struct ieee80211_radiotap_header *hdr =
-               (struct ieee80211_radiotap_header *) skb->data;
 
-       return le16_to_cpu(hdr->it_len);
-}
+/* regular interfaces */
 
-#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
-static void ieee80211_dump_frame(const char *ifname, const char *title,
-                                const struct sk_buff *skb)
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
-       const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 fc;
-       int hdrlen;
-
-       printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
-       if (skb->len < 4) {
-               printk("\n");
-               return;
+       /* FIX: what would be proper limits for MTU?
+        * This interface uses 802.3 frames. */
+       if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+               printk(KERN_WARNING "%s: invalid MTU %d\n",
+                      dev->name, new_mtu);
+               return -EINVAL;
        }
 
-       fc = le16_to_cpu(hdr->frame_control);
-       hdrlen = ieee80211_get_hdrlen(fc);
-       if (hdrlen > skb->len)
-               hdrlen = skb->len;
-       if (hdrlen >= 4)
-               printk(" FC=0x%04x DUR=0x%04x",
-                      fc, le16_to_cpu(hdr->duration_id));
-       if (hdrlen >= 10)
-               printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1));
-       if (hdrlen >= 16)
-               printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
-       if (hdrlen >= 24)
-               printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
-       if (hdrlen >= 30)
-               printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
-       printk("\n");
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       dev->mtu = new_mtu;
+       return 0;
 }
-#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-static inline void ieee80211_dump_frame(const char *ifname, const char *title,
-                                       struct sk_buff *skb)
+
+static inline int identical_mac_addr_allowed(int type1, int type2)
 {
+       return (type1 == IEEE80211_IF_TYPE_MNTR ||
+               type2 == IEEE80211_IF_TYPE_MNTR ||
+               (type1 == IEEE80211_IF_TYPE_AP &&
+                type2 == IEEE80211_IF_TYPE_WDS) ||
+               (type1 == IEEE80211_IF_TYPE_WDS &&
+                (type2 == IEEE80211_IF_TYPE_WDS ||
+                 type2 == IEEE80211_IF_TYPE_AP)) ||
+               (type1 == IEEE80211_IF_TYPE_AP &&
+                type2 == IEEE80211_IF_TYPE_VLAN) ||
+               (type1 == IEEE80211_IF_TYPE_VLAN &&
+                (type2 == IEEE80211_IF_TYPE_AP ||
+                 type2 == IEEE80211_IF_TYPE_VLAN)));
 }
-#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-
 
-static int ieee80211_is_eapol(const struct sk_buff *skb)
+static int ieee80211_open(struct net_device *dev)
 {
-       const struct ieee80211_hdr *hdr;
-       u16 fc;
-       int hdrlen;
-
-       if (unlikely(skb->len < 10))
-               return 0;
-
-       hdr = (const struct ieee80211_hdr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
-
-       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-               return 0;
-
-       hdrlen = ieee80211_get_hdrlen(fc);
+       struct ieee80211_sub_if_data *sdata, *nsdata;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_if_init_conf conf;
+       int res;
 
-       if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
-                    memcmp(skb->data + hdrlen, eapol_header,
-                           sizeof(eapol_header)) == 0))
-               return 1;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       return 0;
-}
+       /* we hold the RTNL here so can safely walk the list */
+       list_for_each_entry(nsdata, &local->interfaces, list) {
+               struct net_device *ndev = nsdata->dev;
 
+               if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
+                   compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
+                       /*
+                        * check whether it may have the same address
+                        */
+                       if (!identical_mac_addr_allowed(sdata->type,
+                                                       nsdata->type))
+                               return -ENOTUNIQ;
 
-static ieee80211_txrx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
-{
-       struct rate_control_extra extra;
-
-       memset(&extra, 0, sizeof(extra));
-       extra.mode = tx->u.tx.mode;
-       extra.mgmt_data = tx->sdata &&
-               tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
-       extra.ethertype = tx->ethertype;
-
-       tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
-                                             &extra);
-       if (unlikely(extra.probe != NULL)) {
-               tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE;
-               tx->u.tx.probe_last_frag = 1;
-               tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
-               tx->u.tx.rate = extra.probe;
-       } else {
-               tx->u.tx.control->alt_retry_rate = -1;
-       }
-       if (!tx->u.tx.rate)
-               return TXRX_DROP;
-       if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
-           tx->local->cts_protect_erp_frames && tx->fragmented &&
-           extra.nonerp) {
-               tx->u.tx.last_frag_rate = tx->u.tx.rate;
-               tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
-
-               tx->u.tx.rate = extra.nonerp;
-               tx->u.tx.control->rate = extra.nonerp;
-               tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
-       } else {
-               tx->u.tx.last_frag_rate = tx->u.tx.rate;
-               tx->u.tx.control->rate = tx->u.tx.rate;
+                       /*
+                        * can only add VLANs to enabled APs
+                        */
+                       if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
+                           nsdata->type == IEEE80211_IF_TYPE_AP &&
+                           netif_running(nsdata->dev))
+                               sdata->u.vlan.ap = nsdata;
+               }
        }
-       tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
-       if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
-           tx->local->short_preamble &&
-           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-               tx->u.tx.short_preamble = 1;
-               tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_WDS:
+               if (is_zero_ether_addr(sdata->u.wds.remote_addr))
+                       return -ENOLINK;
+               break;
+       case IEEE80211_IF_TYPE_VLAN:
+               if (!sdata->u.vlan.ap)
+                       return -ENOLINK;
+               break;
+       case IEEE80211_IF_TYPE_AP:
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_MNTR:
+       case IEEE80211_IF_TYPE_IBSS:
+               /* no special treatment */
+               break;
+       case IEEE80211_IF_TYPE_INVALID:
+               /* cannot happen */
+               WARN_ON(1);
+               break;
        }
 
-       return TXRX_CONTINUE;
-}
+       if (local->open_count == 0) {
+               res = 0;
+               if (local->ops->start)
+                       res = local->ops->start(local_to_hw(local));
+               if (res)
+                       return res;
+       }
 
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_VLAN:
+               list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
+               /* no need to tell driver */
+               break;
+       case IEEE80211_IF_TYPE_MNTR:
+               /* must be before the call to ieee80211_configure_filter */
+               local->monitors++;
+               if (local->monitors == 1) {
+                       netif_tx_lock_bh(local->mdev);
+                       ieee80211_configure_filter(local);
+                       netif_tx_unlock_bh(local->mdev);
 
-static ieee80211_txrx_result
-ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
-{
-       if (tx->sta)
-               tx->u.tx.control->key_idx = tx->sta->key_idx_compression;
-       else
-               tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
-
-       if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
-               tx->key = NULL;
-       else if (tx->sta && tx->sta->key)
-               tx->key = tx->sta->key;
-       else if (tx->sdata->default_key)
-               tx->key = tx->sdata->default_key;
-       else if (tx->sdata->drop_unencrypted &&
-                !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
-               I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-               return TXRX_DROP;
-       } else
-               tx->key = NULL;
-
-       if (tx->key) {
-               tx->key->tx_rx_count++;
-               if (unlikely(tx->local->key_tx_rx_threshold &&
-                            tx->key->tx_rx_count >
-                            tx->local->key_tx_rx_threshold)) {
-                       ieee80211_key_threshold_notify(tx->dev, tx->key,
-                                                      tx->sta);
+                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+                       ieee80211_hw_config(local);
                }
-       }
-
-       return TXRX_CONTINUE;
-}
+               break;
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
+               sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+               /* fall through */
+       default:
+               conf.if_id = dev->ifindex;
+               conf.type = sdata->type;
+               conf.mac_addr = dev->dev_addr;
+               res = local->ops->add_interface(local_to_hw(local), &conf);
+               if (res && !local->open_count && local->ops->stop)
+                       local->ops->stop(local_to_hw(local));
+               if (res)
+                       return res;
 
+               ieee80211_if_config(dev);
+               ieee80211_reset_erp_info(dev);
+               ieee80211_enable_keys(sdata);
 
-static ieee80211_txrx_result
-ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       size_t hdrlen, per_fragm, num_fragm, payload_len, left;
-       struct sk_buff **frags, *first, *frag;
-       int i;
-       u16 seq;
-       u8 *pos;
-       int frag_threshold = tx->local->fragmentation_threshold;
-
-       if (!tx->fragmented)
-               return TXRX_CONTINUE;
-
-       first = tx->skb;
-
-       hdrlen = ieee80211_get_hdrlen(tx->fc);
-       payload_len = first->len - hdrlen;
-       per_fragm = frag_threshold - hdrlen - FCS_LEN;
-       num_fragm = (payload_len + per_fragm - 1) / per_fragm;
-
-       frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
-       if (!frags)
-               goto fail;
-
-       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
-       seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
-       pos = first->data + hdrlen + per_fragm;
-       left = payload_len - per_fragm;
-       for (i = 0; i < num_fragm - 1; i++) {
-               struct ieee80211_hdr *fhdr;
-               size_t copylen;
-
-               if (left <= 0)
-                       goto fail;
-
-               /* reserve enough extra head and tail room for possible
-                * encryption */
-               frag = frags[i] =
-                       dev_alloc_skb(tx->local->hw.extra_tx_headroom +
-                                     frag_threshold +
-                                     IEEE80211_ENCRYPT_HEADROOM +
-                                     IEEE80211_ENCRYPT_TAILROOM);
-               if (!frag)
-                       goto fail;
-               /* Make sure that all fragments use the same priority so
-                * that they end up using the same TX queue */
-               frag->priority = first->priority;
-               skb_reserve(frag, tx->local->hw.extra_tx_headroom +
-                       IEEE80211_ENCRYPT_HEADROOM);
-               fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
-               memcpy(fhdr, first->data, hdrlen);
-               if (i == num_fragm - 2)
-                       fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
-               fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
-               copylen = left > per_fragm ? per_fragm : left;
-               memcpy(skb_put(frag, copylen), pos, copylen);
-
-               pos += copylen;
-               left -= copylen;
+               if (sdata->type == IEEE80211_IF_TYPE_STA &&
+                   !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+                       netif_carrier_off(dev);
+               else
+                       netif_carrier_on(dev);
        }
-       skb_trim(first, hdrlen + per_fragm);
-
-       tx->u.tx.num_extra_frag = num_fragm - 1;
-       tx->u.tx.extra_frag = frags;
 
-       return TXRX_CONTINUE;
-
- fail:
-       printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
-       if (frags) {
-               for (i = 0; i < num_fragm - 1; i++)
-                       if (frags[i])
-                               dev_kfree_skb(frags[i]);
-               kfree(frags);
+       if (local->open_count == 0) {
+               res = dev_open(local->mdev);
+               WARN_ON(res);
+               tasklet_enable(&local->tx_pending_tasklet);
+               tasklet_enable(&local->tasklet);
        }
-       I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
-       return TXRX_DROP;
-}
-
 
-static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
-{
-       if (tx->key->force_sw_encrypt) {
-               if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
-                       return -1;
-       } else {
-               tx->u.tx.control->key_idx = tx->key->hw_key_idx;
-               if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
-                       if (ieee80211_wep_add_iv(tx->local, skb, tx->key) ==
-                           NULL)
-                               return -1;
-               }
-       }
-       return 0;
-}
+       local->open_count++;
 
+       netif_start_queue(dev);
 
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-
-       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-       if (tx->u.tx.extra_frag) {
-               struct ieee80211_hdr *fhdr;
-               int i;
-               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-                       fhdr = (struct ieee80211_hdr *)
-                               tx->u.tx.extra_frag[i]->data;
-                       fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-               }
-       }
+       return 0;
 }
 
-
-static ieee80211_txrx_result
-ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx)
+static int ieee80211_stop(struct net_device *dev)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_if_init_conf conf;
 
-       fc = le16_to_cpu(hdr->frame_control);
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (!tx->key || tx->key->alg != ALG_WEP ||
-           ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
-            ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-             (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
-               return TXRX_CONTINUE;
+       netif_stop_queue(dev);
 
-       tx->u.tx.control->iv_len = WEP_IV_LEN;
-       tx->u.tx.control->icv_len = WEP_ICV_LEN;
-       ieee80211_tx_set_iswep(tx);
+       dev_mc_unsync(local->mdev, dev);
 
-       if (wep_encrypt_skb(tx, tx->skb) < 0) {
-               I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
-               return TXRX_DROP;
-       }
+       /* down all dependent devices, that is VLANs */
+       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+               struct ieee80211_sub_if_data *vlan, *tmp;
 
-       if (tx->u.tx.extra_frag) {
-               int i;
-               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-                       if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
-                               I802_DEBUG_INC(tx->local->
-                                              tx_handlers_drop_wep);
-                               return TXRX_DROP;
-                       }
-               }
+               list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
+                                        u.vlan.list)
+                       dev_close(vlan->dev);
+               WARN_ON(!list_empty(&sdata->u.ap.vlans));
        }
 
-       return TXRX_CONTINUE;
-}
-
-
-static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
-                                   int rate, int erp, int short_preamble)
-{
-       int dur;
+       local->open_count--;
 
-       /* calculate duration (in microseconds, rounded up to next higher
-        * integer if it includes a fractional microsecond) to send frame of
-        * len bytes (does not include FCS) at the given rate. Duration will
-        * also include SIFS.
-        *
-        * rate is in 100 kbps, so divident is multiplied by 10 in the
-        * DIV_ROUND_UP() operations.
-        */
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_VLAN:
+               list_del(&sdata->u.vlan.list);
+               sdata->u.vlan.ap = NULL;
+               /* no need to tell driver */
+               break;
+       case IEEE80211_IF_TYPE_MNTR:
+               local->monitors--;
+               if (local->monitors == 0) {
+                       netif_tx_lock_bh(local->mdev);
+                       ieee80211_configure_filter(local);
+                       netif_tx_unlock_bh(local->mdev);
 
-       if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
-           local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
-               /*
-                * OFDM:
-                *
-                * N_DBPS = DATARATE x 4
-                * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
-                *      (16 = SIGNAL time, 6 = tail bits)
-                * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
-                *
-                * T_SYM = 4 usec
-                * 802.11a - 17.5.2: aSIFSTime = 16 usec
-                * 802.11g - 19.8.4: aSIFSTime = 10 usec +
-                *      signal ext = 6 usec
-                */
-               /* FIX: Atheros Turbo may have different (shorter) duration? */
-               dur = 16; /* SIFS + signal ext */
-               dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
-               dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
-               dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
-                                       4 * rate); /* T_SYM x N_SYM */
-       } else {
+                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+                       ieee80211_hw_config(local);
+               }
+               break;
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
+               sdata->u.sta.state = IEEE80211_DISABLED;
+               del_timer_sync(&sdata->u.sta.timer);
                /*
-                * 802.11b or 802.11g with 802.11b compatibility:
-                * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
-                * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
-                *
-                * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
-                * aSIFSTime = 10 usec
-                * aPreambleLength = 144 usec or 72 usec with short preamble
-                * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+                * When we get here, the interface is marked down.
+                * Call synchronize_rcu() to wait for the RX path
+                * should it be using the interface and enqueuing
+                * frames at this very time on another CPU.
                 */
-               dur = 10; /* aSIFSTime = 10 usec */
-               dur += short_preamble ? (72 + 24) : (144 + 48);
+               synchronize_rcu();
+               skb_queue_purge(&sdata->u.sta.skb_queue);
 
-               dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+               if (!local->ops->hw_scan &&
+                   local->scan_dev == sdata->dev) {
+                       local->sta_scanning = 0;
+                       cancel_delayed_work(&local->scan_work);
+               }
+               flush_workqueue(local->hw.workqueue);
+               /* fall through */
+       default:
+               conf.if_id = dev->ifindex;
+               conf.type = sdata->type;
+               conf.mac_addr = dev->dev_addr;
+               /* disable all keys for as long as this netdev is down */
+               ieee80211_disable_keys(sdata);
+               local->ops->remove_interface(local_to_hw(local), &conf);
        }
 
-       return dur;
-}
-
-
-/* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
-                                       size_t frame_len, int rate)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       u16 dur;
-       int erp;
-
-       erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
-       dur = ieee80211_frame_duration(local, frame_len, rate,
-                                      erp, local->short_preamble);
-
-       return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_generic_frame_duration);
-
+       if (local->open_count == 0) {
+               if (netif_running(local->mdev))
+                       dev_close(local->mdev);
 
-static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
-                             int next_frag_len)
-{
-       int rate, mrate, erp, dur, i;
-       struct ieee80211_rate *txrate = tx->u.tx.rate;
-       struct ieee80211_local *local = tx->local;
-       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+               if (local->ops->stop)
+                       local->ops->stop(local_to_hw(local));
 
-       erp = txrate->flags & IEEE80211_RATE_ERP;
-
-       /*
-        * data and mgmt (except PS Poll):
-        * - during CFP: 32768
-        * - during contention period:
-        *   if addr1 is group address: 0
-        *   if more fragments = 0 and addr1 is individual address: time to
-        *      transmit one ACK plus SIFS
-        *   if more fragments = 1 and addr1 is individual address: time to
-        *      transmit next fragment plus 2 x ACK plus 3 x SIFS
-        *
-        * IEEE 802.11, 9.6:
-        * - control response frame (CTS or ACK) shall be transmitted using the
-        *   same rate as the immediately previous frame in the frame exchange
-        *   sequence, if this rate belongs to the PHY mandatory rates, or else
-        *   at the highest possible rate belonging to the PHY rates in the
-        *   BSSBasicRateSet
-        */
-
-       if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {
-               /* TODO: These control frames are not currently sent by
-                * 80211.o, but should they be implemented, this function
-                * needs to be updated to support duration field calculation.
-                *
-                * RTS: time needed to transmit pending data/mgmt frame plus
-                *    one CTS frame plus one ACK frame plus 3 x SIFS
-                * CTS: duration of immediately previous RTS minus time
-                *    required to transmit CTS and its SIFS
-                * ACK: 0 if immediately previous directed data/mgmt had
-                *    more=0, with more=1 duration in ACK frame is duration
-                *    from previous frame minus time needed to transmit ACK
-                *    and its SIFS
-                * PS Poll: BIT(15) | BIT(14) | aid
-                */
-               return 0;
-       }
-
-       /* data/mgmt */
-       if (0 /* FIX: data/mgmt during CFP */)
-               return 32768;
-
-       if (group_addr) /* Group address as the destination - no ACK */
-               return 0;
-
-       /* Individual destination address:
-        * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
-        * CTS and ACK frames shall be transmitted using the highest rate in
-        * basic rate set that is less than or equal to the rate of the
-        * immediately previous frame and that is using the same modulation
-        * (CCK or OFDM). If no basic rate set matches with these requirements,
-        * the highest mandatory rate of the PHY that is less than or equal to
-        * the rate of the previous frame is used.
-        * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
-        */
-       rate = -1;
-       mrate = 10; /* use 1 Mbps if everything fails */
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *r = &mode->rates[i];
-               if (r->rate > txrate->rate)
-                       break;
-
-               if (IEEE80211_RATE_MODULATION(txrate->flags) !=
-                   IEEE80211_RATE_MODULATION(r->flags))
-                       continue;
-
-               if (r->flags & IEEE80211_RATE_BASIC)
-                       rate = r->rate;
-               else if (r->flags & IEEE80211_RATE_MANDATORY)
-                       mrate = r->rate;
-       }
-       if (rate == -1) {
-               /* No matching basic rate found; use highest suitable mandatory
-                * PHY rate */
-               rate = mrate;
-       }
-
-       /* Time needed to transmit ACK
-        * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
-        * to closest integer */
-
-       dur = ieee80211_frame_duration(local, 10, rate, erp,
-                                      local->short_preamble);
-
-       if (next_frag_len) {
-               /* Frame is fragmented: duration increases with time needed to
-                * transmit next fragment plus ACK and 2 x SIFS. */
-               dur *= 2; /* ACK + SIFS */
-               /* next fragment */
-               dur += ieee80211_frame_duration(local, next_frag_len,
-                                               txrate->rate, erp,
-                                               local->short_preamble);
-       }
-
-       return dur;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 dur;
-       struct ieee80211_tx_control *control = tx->u.tx.control;
-       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
-
-       if (!is_multicast_ether_addr(hdr->addr1)) {
-               if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
-                   tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
-                       control->flags |= IEEE80211_TXCTL_USE_RTS_CTS;
-                       control->retry_limit =
-                               tx->local->long_retry_limit;
-               } else {
-                       control->retry_limit =
-                               tx->local->short_retry_limit;
-               }
-       } else {
-               control->retry_limit = 1;
-       }
-
-       if (tx->fragmented) {
-               /* Do not use multiple retry rates when sending fragmented
-                * frames.
-                * TODO: The last fragment could still use multiple retry
-                * rates. */
-               control->alt_retry_rate = -1;
-       }
-
-       /* Use CTS protection for unicast frames sent using extended rates if
-        * there are associated non-ERP stations and RTS/CTS is not configured
-        * for the frame. */
-       if (mode->mode == MODE_IEEE80211G &&
-           (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
-           tx->u.tx.unicast &&
-           tx->local->cts_protect_erp_frames &&
-           !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
-               control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
-
-       /* Setup duration field for the first fragment of the frame. Duration
-        * for remaining fragments will be updated when they are being sent
-        * to low-level driver in ieee80211_tx(). */
-       dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
-                                tx->fragmented ? tx->u.tx.extra_frag[0]->len :
-                                0);
-       hdr->duration_id = cpu_to_le16(dur);
-
-       if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
-           (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
-               struct ieee80211_rate *rate;
-
-               /* Do not use multiple retry rates when using RTS/CTS */
-               control->alt_retry_rate = -1;
-
-               /* Use min(data rate, max base rate) as CTS/RTS rate */
-               rate = tx->u.tx.rate;
-               while (rate > mode->rates &&
-                      !(rate->flags & IEEE80211_RATE_BASIC))
-                       rate--;
-
-               control->rts_cts_rate = rate->val;
-               control->rts_rate = rate;
-       }
-
-       if (tx->sta) {
-               tx->sta->tx_packets++;
-               tx->sta->tx_fragments++;
-               tx->sta->tx_bytes += tx->skb->len;
-               if (tx->u.tx.extra_frag) {
-                       int i;
-                       tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
-                       for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-                               tx->sta->tx_bytes +=
-                                       tx->u.tx.extra_frag[i]->len;
-                       }
-               }
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
-{
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       struct sk_buff *skb = tx->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-       u32 sta_flags;
-
-       if (unlikely(tx->local->sta_scanning != 0) &&
-           ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-            (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
-               return TXRX_DROP;
-
-       if (tx->u.tx.ps_buffered)
-               return TXRX_CONTINUE;
-
-       sta_flags = tx->sta ? tx->sta->flags : 0;
-
-       if (likely(tx->u.tx.unicast)) {
-               if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
-                            tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
-                            (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       printk(KERN_DEBUG "%s: dropped data frame to not "
-                              "associated station " MAC_FMT "\n",
-                              tx->dev->name, MAC_ARG(hdr->addr1));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-                       I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
-                       return TXRX_DROP;
-               }
-       } else {
-               if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-                            tx->local->num_sta == 0 &&
-                            !tx->local->allow_broadcast_always &&
-                            tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
-                       /*
-                        * No associated STAs - no need to send multicast
-                        * frames.
-                        */
-                       return TXRX_DROP;
-               }
-               return TXRX_CONTINUE;
-       }
-
-       if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
-                    !(sta_flags & WLAN_STA_AUTHORIZED))) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
-                      " (unauthorized port)\n", tx->dev->name,
-                      MAC_ARG(hdr->addr1));
-#endif
-               I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
-               return TXRX_DROP;
-       }
-
-       return TXRX_CONTINUE;
-}
-
-static ieee80211_txrx_result
-ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-
-       if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
-               ieee80211_include_sequence(tx->sdata, hdr);
-
-       return TXRX_CONTINUE;
-}
-
-/* This function is called whenever the AP is about to exceed the maximum limit
- * of buffered frames for power saving STAs. This situation should not really
- * happen often during normal operation, so dropping the oldest buffered packet
- * from each queue should be OK to make some room for new frames. */
-static void purge_old_ps_buffers(struct ieee80211_local *local)
-{
-       int total = 0, purged = 0;
-       struct sk_buff *skb;
-       struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta;
-
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
-               struct ieee80211_if_ap *ap;
-               if (sdata->dev == local->mdev ||
-                   sdata->type != IEEE80211_IF_TYPE_AP)
-                       continue;
-               ap = &sdata->u.ap;
-               skb = skb_dequeue(&ap->ps_bc_buf);
-               if (skb) {
-                       purged++;
-                       dev_kfree_skb(skb);
-               }
-               total += skb_queue_len(&ap->ps_bc_buf);
-       }
-       read_unlock(&local->sub_if_lock);
-
-       spin_lock_bh(&local->sta_lock);
-       list_for_each_entry(sta, &local->sta_list, list) {
-               skb = skb_dequeue(&sta->ps_tx_buf);
-               if (skb) {
-                       purged++;
-                       dev_kfree_skb(skb);
-               }
-               total += skb_queue_len(&sta->ps_tx_buf);
-       }
-       spin_unlock_bh(&local->sta_lock);
-
-       local->total_ps_buffered = total;
-       printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
-              local->mdev->name, purged);
-}
-
-
-static inline ieee80211_txrx_result
-ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
-{
-       /* broadcast/multicast frame */
-       /* If any of the associated stations is in power save mode,
-        * the frame is buffered to be sent after DTIM beacon frame */
-       if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&
-           tx->sdata->type != IEEE80211_IF_TYPE_WDS &&
-           tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&
-           !(tx->fc & IEEE80211_FCTL_ORDER)) {
-               if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
-                       purge_old_ps_buffers(tx->local);
-               if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
-                   AP_MAX_BC_BUFFER) {
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: BC TX buffer full - "
-                                      "dropping the oldest frame\n",
-                                      tx->dev->name);
-                       }
-                       dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
-               } else
-                       tx->local->total_ps_buffered++;
-               skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
-               return TXRX_QUEUED;
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static inline ieee80211_txrx_result
-ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
-{
-       struct sta_info *sta = tx->sta;
-
-       if (unlikely(!sta ||
-                    ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
-                     (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
-               return TXRX_CONTINUE;
-
-       if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
-               struct ieee80211_tx_packet_data *pkt_data;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries "
-                      "before %d)\n",
-                      MAC_ARG(sta->addr), sta->aid,
-                      skb_queue_len(&sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               sta->flags |= WLAN_STA_TIM;
-               if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
-                       purge_old_ps_buffers(tx->local);
-               if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
-                       struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: STA " MAC_FMT " TX "
-                                      "buffer full - dropping oldest frame\n",
-                                      tx->dev->name, MAC_ARG(sta->addr));
-                       }
-                       dev_kfree_skb(old);
-               } else
-                       tx->local->total_ps_buffered++;
-               /* Queue frame to be sent after STA sends an PS Poll frame */
-               if (skb_queue_empty(&sta->ps_tx_buf)) {
-                       if (tx->local->ops->set_tim)
-                               tx->local->ops->set_tim(local_to_hw(tx->local),
-                                                      sta->aid, 1);
-                       if (tx->sdata->bss)
-                               bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
-               }
-               pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
-               pkt_data->jiffies = jiffies;
-               skb_queue_tail(&sta->ps_tx_buf, tx->skb);
-               return TXRX_QUEUED;
-       }
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(sta->flags & WLAN_STA_PS)) {
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll "
-                      "set -> send frame\n", tx->dev->name,
-                      MAC_ARG(sta->addr));
-       }
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       sta->pspoll = 0;
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
-{
-       if (unlikely(tx->u.tx.ps_buffered))
-               return TXRX_CONTINUE;
-
-       if (tx->u.tx.unicast)
-               return ieee80211_tx_h_unicast_ps_buf(tx);
-       else
-               return ieee80211_tx_h_multicast_ps_buf(tx);
-}
-
-
-static void inline
-__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
-                      struct sk_buff *skb,
-                      struct net_device *dev,
-                      struct ieee80211_tx_control *control)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       int hdrlen;
-
-       memset(tx, 0, sizeof(*tx));
-       tx->skb = skb;
-       tx->dev = dev; /* use original interface */
-       tx->local = local;
-       tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       tx->sta = sta_info_get(local, hdr->addr1);
-       tx->fc = le16_to_cpu(hdr->frame_control);
-       control->power_level = local->hw.conf.power_level;
-       tx->u.tx.control = control;
-       tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
-       if (is_multicast_ether_addr(hdr->addr1))
-               control->flags |= IEEE80211_TXCTL_NO_ACK;
-       else
-               control->flags &= ~IEEE80211_TXCTL_NO_ACK;
-       tx->fragmented = local->fragmentation_threshold <
-               IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast &&
-               skb->len + FCS_LEN > local->fragmentation_threshold &&
-               (!local->ops->set_frag_threshold);
-       if (!tx->sta)
-               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
-       else if (tx->sta->clear_dst_mask) {
-               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
-               tx->sta->clear_dst_mask = 0;
-       }
-       control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-       if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
-               control->antenna_sel_tx = tx->sta->antenna_sel_tx;
-       hdrlen = ieee80211_get_hdrlen(tx->fc);
-       if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
-               u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
-               tx->ethertype = (pos[0] << 8) | pos[1];
-       }
-       control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
-
-}
-
-static int inline is_ieee80211_device(struct net_device *dev,
-                                     struct net_device *master)
-{
-       return (wdev_priv(dev->ieee80211_ptr) ==
-               wdev_priv(master->ieee80211_ptr));
-}
-
-/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
- * finished with it. */
-static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
-                                      struct sk_buff *skb,
-                                      struct net_device *mdev,
-                                      struct ieee80211_tx_control *control)
-{
-       struct ieee80211_tx_packet_data *pkt_data;
-       struct net_device *dev;
-
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       dev = dev_get_by_index(pkt_data->ifindex);
-       if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
-               dev_put(dev);
-               dev = NULL;
-       }
-       if (unlikely(!dev))
-               return -ENODEV;
-       __ieee80211_tx_prepare(tx, skb, dev, control);
-       return 0;
-}
-
-static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
-                                           int queue)
-{
-       return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-
-static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
-                                           int queue)
-{
-       return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
-}
-
-#define IEEE80211_TX_OK                0
-#define IEEE80211_TX_AGAIN     1
-#define IEEE80211_TX_FRAG_AGAIN        2
-
-static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
-                         struct ieee80211_txrx_data *tx)
-{
-       struct ieee80211_tx_control *control = tx->u.tx.control;
-       int ret, i;
-
-       if (!ieee80211_qdisc_installed(local->mdev) &&
-           __ieee80211_queue_stopped(local, 0)) {
-               netif_stop_queue(local->mdev);
-               return IEEE80211_TX_AGAIN;
-       }
-       if (skb) {
-               ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
-               ret = local->ops->tx(local_to_hw(local), skb, control);
-               if (ret)
-                       return IEEE80211_TX_AGAIN;
-               local->mdev->trans_start = jiffies;
-               ieee80211_led_tx(local, 1);
-       }
-       if (tx->u.tx.extra_frag) {
-               control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
-                                   IEEE80211_TXCTL_USE_CTS_PROTECT |
-                                   IEEE80211_TXCTL_CLEAR_DST_MASK |
-                                   IEEE80211_TXCTL_FIRST_FRAGMENT);
-               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-                       if (!tx->u.tx.extra_frag[i])
-                               continue;
-                       if (__ieee80211_queue_stopped(local, control->queue))
-                               return IEEE80211_TX_FRAG_AGAIN;
-                       if (i == tx->u.tx.num_extra_frag) {
-                               control->tx_rate = tx->u.tx.last_frag_hwrate;
-                               control->rate = tx->u.tx.last_frag_rate;
-                               if (tx->u.tx.probe_last_frag)
-                                       control->flags |=
-                                               IEEE80211_TXCTL_RATE_CTRL_PROBE;
-                               else
-                                       control->flags &=
-                                               ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
-                       }
-
-                       ieee80211_dump_frame(local->mdev->name,
-                                            "TX to low-level driver",
-                                            tx->u.tx.extra_frag[i]);
-                       ret = local->ops->tx(local_to_hw(local),
-                                           tx->u.tx.extra_frag[i],
-                                           control);
-                       if (ret)
-                               return IEEE80211_TX_FRAG_AGAIN;
-                       local->mdev->trans_start = jiffies;
-                       ieee80211_led_tx(local, 1);
-                       tx->u.tx.extra_frag[i] = NULL;
-               }
-               kfree(tx->u.tx.extra_frag);
-               tx->u.tx.extra_frag = NULL;
-       }
-       return IEEE80211_TX_OK;
-}
-
-static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
-                       struct ieee80211_tx_control *control, int mgmt)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-       ieee80211_tx_handler *handler;
-       struct ieee80211_txrx_data tx;
-       ieee80211_txrx_result res = TXRX_DROP;
-       int ret, i;
-
-       WARN_ON(__ieee80211_queue_pending(local, control->queue));
-
-       if (unlikely(skb->len < 10)) {
-               dev_kfree_skb(skb);
-               return 0;
-       }
-
-       __ieee80211_tx_prepare(&tx, skb, dev, control);
-       sta = tx.sta;
-       tx.u.tx.mgmt_interface = mgmt;
-       tx.u.tx.mode = local->hw.conf.mode;
-
-       for (handler = local->tx_handlers; *handler != NULL; handler++) {
-               res = (*handler)(&tx);
-               if (res != TXRX_CONTINUE)
-                       break;
-       }
-
-       skb = tx.skb; /* handlers are allowed to change skb */
-
-       if (sta)
-               sta_info_put(sta);
-
-       if (unlikely(res == TXRX_DROP)) {
-               I802_DEBUG_INC(local->tx_handlers_drop);
-               goto drop;
-       }
-
-       if (unlikely(res == TXRX_QUEUED)) {
-               I802_DEBUG_INC(local->tx_handlers_queued);
-               return 0;
-       }
-
-       if (tx.u.tx.extra_frag) {
-               for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
-                       int next_len, dur;
-                       struct ieee80211_hdr *hdr =
-                               (struct ieee80211_hdr *)
-                               tx.u.tx.extra_frag[i]->data;
-
-                       if (i + 1 < tx.u.tx.num_extra_frag) {
-                               next_len = tx.u.tx.extra_frag[i + 1]->len;
-                       } else {
-                               next_len = 0;
-                               tx.u.tx.rate = tx.u.tx.last_frag_rate;
-                               tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
-                       }
-                       dur = ieee80211_duration(&tx, 0, next_len);
-                       hdr->duration_id = cpu_to_le16(dur);
-               }
-       }
-
-retry:
-       ret = __ieee80211_tx(local, skb, &tx);
-       if (ret) {
-               struct ieee80211_tx_stored_packet *store =
-                       &local->pending_packet[control->queue];
-
-               if (ret == IEEE80211_TX_FRAG_AGAIN)
-                       skb = NULL;
-               set_bit(IEEE80211_LINK_STATE_PENDING,
-                       &local->state[control->queue]);
-               smp_mb();
-               /* When the driver gets out of buffers during sending of
-                * fragments and calls ieee80211_stop_queue, there is
-                * a small window between IEEE80211_LINK_STATE_XOFF and
-                * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
-                * gets available in that window (i.e. driver calls
-                * ieee80211_wake_queue), we would end up with ieee80211_tx
-                * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
-                * continuing transmitting here when that situation is
-                * possible to have happened. */
-               if (!__ieee80211_queue_stopped(local, control->queue)) {
-                       clear_bit(IEEE80211_LINK_STATE_PENDING,
-                                 &local->state[control->queue]);
-                       goto retry;
-               }
-               memcpy(&store->control, control,
-                      sizeof(struct ieee80211_tx_control));
-               store->skb = skb;
-               store->extra_frag = tx.u.tx.extra_frag;
-               store->num_extra_frag = tx.u.tx.num_extra_frag;
-               store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
-               store->last_frag_rate = tx.u.tx.last_frag_rate;
-               store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
-       }
-       return 0;
-
- drop:
-       if (skb)
-               dev_kfree_skb(skb);
-       for (i = 0; i < tx.u.tx.num_extra_frag; i++)
-               if (tx.u.tx.extra_frag[i])
-                       dev_kfree_skb(tx.u.tx.extra_frag[i]);
-       kfree(tx.u.tx.extra_frag);
-       return 0;
-}
-
-static void ieee80211_tx_pending(unsigned long data)
-{
-       struct ieee80211_local *local = (struct ieee80211_local *)data;
-       struct net_device *dev = local->mdev;
-       struct ieee80211_tx_stored_packet *store;
-       struct ieee80211_txrx_data tx;
-       int i, ret, reschedule = 0;
-
-       netif_tx_lock_bh(dev);
-       for (i = 0; i < local->hw.queues; i++) {
-               if (__ieee80211_queue_stopped(local, i))
-                       continue;
-               if (!__ieee80211_queue_pending(local, i)) {
-                       reschedule = 1;
-                       continue;
-               }
-               store = &local->pending_packet[i];
-               tx.u.tx.control = &store->control;
-               tx.u.tx.extra_frag = store->extra_frag;
-               tx.u.tx.num_extra_frag = store->num_extra_frag;
-               tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
-               tx.u.tx.last_frag_rate = store->last_frag_rate;
-               tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
-               ret = __ieee80211_tx(local, store->skb, &tx);
-               if (ret) {
-                       if (ret == IEEE80211_TX_FRAG_AGAIN)
-                               store->skb = NULL;
-               } else {
-                       clear_bit(IEEE80211_LINK_STATE_PENDING,
-                                 &local->state[i]);
-                       reschedule = 1;
-               }
-       }
-       netif_tx_unlock_bh(dev);
-       if (reschedule) {
-               if (!ieee80211_qdisc_installed(dev)) {
-                       if (!__ieee80211_queue_stopped(local, 0))
-                               netif_wake_queue(dev);
-               } else
-                       netif_schedule(dev);
-       }
-}
-
-static void ieee80211_clear_tx_pending(struct ieee80211_local *local)
-{
-       int i, j;
-       struct ieee80211_tx_stored_packet *store;
-
-       for (i = 0; i < local->hw.queues; i++) {
-               if (!__ieee80211_queue_pending(local, i))
-                       continue;
-               store = &local->pending_packet[i];
-               kfree_skb(store->skb);
-               for (j = 0; j < store->num_extra_frag; j++)
-                       kfree_skb(store->extra_frag[j]);
-               kfree(store->extra_frag);
-               clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
-       }
-}
-
-static int ieee80211_master_start_xmit(struct sk_buff *skb,
-                                      struct net_device *dev)
-{
-       struct ieee80211_tx_control control;
-       struct ieee80211_tx_packet_data *pkt_data;
-       struct net_device *odev = NULL;
-       struct ieee80211_sub_if_data *osdata;
-       int headroom;
-       int ret;
-
-       /*
-        * copy control out of the skb so other people can use skb->cb
-        */
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(&control, 0, sizeof(struct ieee80211_tx_control));
-
-       if (pkt_data->ifindex)
-               odev = dev_get_by_index(pkt_data->ifindex);
-       if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
-               dev_put(odev);
-               odev = NULL;
-       }
-       if (unlikely(!odev)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
-                      "originating device\n", dev->name);
-#endif
-               dev_kfree_skb(skb);
-               return 0;
-       }
-       osdata = IEEE80211_DEV_TO_SUB_IF(odev);
-
-       headroom = osdata->local->hw.extra_tx_headroom +
-               IEEE80211_ENCRYPT_HEADROOM;
-       if (skb_headroom(skb) < headroom) {
-               if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
-                       dev_kfree_skb(skb);
-                       return 0;
-               }
-       }
-
-       control.ifindex = odev->ifindex;
-       control.type = osdata->type;
-       if (pkt_data->req_tx_status)
-               control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
-       if (pkt_data->do_not_encrypt)
-               control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-       if (pkt_data->requeue)
-               control.flags |= IEEE80211_TXCTL_REQUEUE;
-       control.queue = pkt_data->queue;
-
-       ret = ieee80211_tx(odev, skb, &control,
-                          control.type == IEEE80211_IF_TYPE_MGMT);
-       dev_put(odev);
-
-       return ret;
-}
-
-
-/**
- * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
- * subinterfaces (wlan#, WDS, and VLAN interfaces)
- * @skb: packet to be sent
- * @dev: incoming interface
- *
- * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
- * not be freed, and caller is responsible for either retrying later or freeing
- * skb).
- *
- * This function takes in an Ethernet header and encapsulates it with suitable
- * IEEE 802.11 header based on which interface the packet is coming in. The
- * encapsulated packet will then be passed to master interface, wlan#.11, for
- * transmission (through low-level driver).
- */
-static int ieee80211_subif_start_xmit(struct sk_buff *skb,
-                                     struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_packet_data *pkt_data;
-       struct ieee80211_sub_if_data *sdata;
-       int ret = 1, head_need;
-       u16 ethertype, hdrlen, fc;
-       struct ieee80211_hdr hdr;
-       const u8 *encaps_data;
-       int encaps_len, skip_header_bytes;
-       int nh_pos, h_pos, no_encrypt = 0;
-       struct sta_info *sta;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (unlikely(skb->len < ETH_HLEN)) {
-               printk(KERN_DEBUG "%s: short skb (len=%d)\n",
-                      dev->name, skb->len);
-               ret = 0;
-               goto fail;
-       }
-
-       nh_pos = skb_network_header(skb) - skb->data;
-       h_pos = skb_transport_header(skb) - skb->data;
-
-       /* convert Ethernet header to proper 802.11 header (based on
-        * operation mode) */
-       ethertype = (skb->data[12] << 8) | skb->data[13];
-       /* TODO: handling for 802.1x authorized/unauthorized port */
-       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
-
-       if (likely(sdata->type == IEEE80211_IF_TYPE_AP ||
-                  sdata->type == IEEE80211_IF_TYPE_VLAN)) {
-               fc |= IEEE80211_FCTL_FROMDS;
-               /* DA BSSID SA */
-               memcpy(hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-               memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
-               hdrlen = 24;
-       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
-               fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
-               /* RA TA DA SA */
-               memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-               memcpy(hdr.addr3, skb->data, ETH_ALEN);
-               memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-               hdrlen = 30;
-       } else if (sdata->type == IEEE80211_IF_TYPE_STA) {
-               if (dls_link_status(local, skb->data) == DLS_STATUS_OK) {
-                       /* DA SA BSSID */
-                       memcpy(hdr.addr1, skb->data, ETH_ALEN);
-                       memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-                       memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
-               } else {
-                       fc |= IEEE80211_FCTL_TODS;
-                       /* BSSID SA DA */
-                       memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
-                       memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-                       memcpy(hdr.addr3, skb->data, ETH_ALEN);
-               }
-               hdrlen = 24;
-       } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               /* DA SA BSSID */
-               memcpy(hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-               memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
-               hdrlen = 24;
-       } else {
-               ret = 0;
-               goto fail;
-       }
-
-       /* receiver is QoS enabled, use a QoS type frame */
-       sta = sta_info_get(local, hdr.addr1);
-       if (sta) {
-               if (sta->flags & WLAN_STA_WME) {
-                       fc |= IEEE80211_STYPE_QOS_DATA;
-                       hdrlen += 2;
-               }
-               sta_info_put(sta);
-       }
-
-       hdr.frame_control = cpu_to_le16(fc);
-       hdr.duration_id = 0;
-       hdr.seq_ctrl = 0;
-
-       skip_header_bytes = ETH_HLEN;
-       if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
-               encaps_data = bridge_tunnel_header;
-               encaps_len = sizeof(bridge_tunnel_header);
-               skip_header_bytes -= 2;
-       } else if (ethertype >= 0x600) {
-               encaps_data = rfc1042_header;
-               encaps_len = sizeof(rfc1042_header);
-               skip_header_bytes -= 2;
-       } else {
-               encaps_data = NULL;
-               encaps_len = 0;
-       }
-
-       skb_pull(skb, skip_header_bytes);
-       nh_pos -= skip_header_bytes;
-       h_pos -= skip_header_bytes;
-
-       /* TODO: implement support for fragments so that there is no need to
-        * reallocate and copy payload; it might be enough to support one
-        * extra fragment that would be copied in the beginning of the frame
-        * data.. anyway, it would be nice to include this into skb structure
-        * somehow
-        *
-        * There are few options for this:
-        * use skb->cb as an extra space for 802.11 header
-        * allocate new buffer if not enough headroom
-        * make sure that there is enough headroom in every skb by increasing
-        * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
-        * alloc_skb() (net/core/skbuff.c)
-        */
-       head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom;
-       head_need -= skb_headroom(skb);
-
-       /* We are going to modify skb data, so make a copy of it if happens to
-        * be cloned. This could happen, e.g., with Linux bridge code passing
-        * us broadcast frames. */
-
-       if (head_need > 0 || skb_cloned(skb)) {
-#if 0
-               printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
-                      "of headroom\n", dev->name, head_need);
-#endif
-
-               if (skb_cloned(skb))
-                       I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
-               else
-                       I802_DEBUG_INC(local->tx_expand_skb_head);
-               /* Since we have to reallocate the buffer, make sure that there
-                * is enough room for possible WEP IV/ICV and TKIP (8 bytes
-                * before payload and 12 after). */
-               if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
-                                    12, GFP_ATOMIC)) {
-                       printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
-                              "\n", dev->name);
-                       goto fail;
-               }
-       }
-
-       if (encaps_data) {
-               memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
-               nh_pos += encaps_len;
-               h_pos += encaps_len;
-       }
-       memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
-       nh_pos += hdrlen;
-       h_pos += hdrlen;
-
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-       pkt_data->ifindex = sdata->dev->ifindex;
-       pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
-       pkt_data->do_not_encrypt = no_encrypt;
-
-       skb->dev = local->mdev;
-       sdata->stats.tx_packets++;
-       sdata->stats.tx_bytes += skb->len;
-
-       /* Update skb pointers to various headers since this modified frame
-        * is going to go through Linux networking code that may potentially
-        * need things like pointer to IP header. */
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, nh_pos);
-       skb_set_transport_header(skb, h_pos);
-
-       dev->trans_start = jiffies;
-       dev_queue_xmit(skb);
-
-       return 0;
-
- fail:
-       if (!ret)
-               dev_kfree_skb(skb);
-
-       return ret;
-}
-
-
-/*
- * This is the transmit routine for the 802.11 type interfaces
- * called by upper layers of the linux networking
- * stack when it has a frame to transmit
- */
-static int
-ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_packet_data *pkt_data;
-       struct ieee80211_hdr *hdr;
-       u16 fc;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (skb->len < 10) {
-               dev_kfree_skb(skb);
-               return 0;
-       }
-
-       if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) {
-               if (pskb_expand_head(skb,
-                   sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) {
-                       dev_kfree_skb(skb);
-                       return 0;
-               }
-       }
-
-       hdr = (struct ieee80211_hdr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
-
-       pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
-       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-       pkt_data->ifindex = sdata->dev->ifindex;
-       pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
-
-       skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
-       skb->dev = sdata->local->mdev;
-
-       /*
-        * We're using the protocol field of the the frame control header
-        * to request TX callback for hostapd. BIT(1) is checked.
-        */
-       if ((fc & BIT(1)) == BIT(1)) {
-               pkt_data->req_tx_status = 1;
-               fc &= ~BIT(1);
-               hdr->frame_control = cpu_to_le16(fc);
-       }
-
-       pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
-
-       sdata->stats.tx_packets++;
-       sdata->stats.tx_bytes += skb->len;
-
-       dev_queue_xmit(skb);
-
-       return 0;
-}
-
-
-static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
-                                    struct ieee80211_if_ap *bss,
-                                    struct sk_buff *skb)
-{
-       u8 *pos, *tim;
-       int aid0 = 0;
-       int i, have_bits = 0, n1, n2;
-
-       /* Generate bitmap for TIM only if there are any STAs in power save
-        * mode. */
-       spin_lock_bh(&local->sta_lock);
-       if (atomic_read(&bss->num_sta_ps) > 0)
-               /* in the hope that this is faster than
-                * checking byte-for-byte */
-               have_bits = !bitmap_empty((unsigned long*)bss->tim,
-                                         IEEE80211_MAX_AID+1);
-
-       if (bss->dtim_count == 0)
-               bss->dtim_count = bss->dtim_period - 1;
-       else
-               bss->dtim_count--;
-
-       tim = pos = (u8 *) skb_put(skb, 6);
-       *pos++ = WLAN_EID_TIM;
-       *pos++ = 4;
-       *pos++ = bss->dtim_count;
-       *pos++ = bss->dtim_period;
-
-       if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
-               aid0 = 1;
-
-       if (have_bits) {
-               /* Find largest even number N1 so that bits numbered 1 through
-                * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
-                * (N2 + 1) x 8 through 2007 are 0. */
-               n1 = 0;
-               for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
-                       if (bss->tim[i]) {
-                               n1 = i & 0xfe;
-                               break;
-                       }
-               }
-               n2 = n1;
-               for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
-                       if (bss->tim[i]) {
-                               n2 = i;
-                               break;
-                       }
-               }
-
-               /* Bitmap control */
-               *pos++ = n1 | aid0;
-               /* Part Virt Bitmap */
-               memcpy(pos, bss->tim + n1, n2 - n1 + 1);
-
-               tim[1] = n2 - n1 + 4;
-               skb_put(skb, n2 - n1);
-       } else {
-               *pos++ = aid0; /* Bitmap control */
-               *pos++ = 0; /* Part Virt Bitmap */
-       }
-       spin_unlock_bh(&local->sta_lock);
-}
-
-
-struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
-                                     struct ieee80211_tx_control *control)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct sk_buff *skb;
-       struct net_device *bdev;
-       struct ieee80211_sub_if_data *sdata = NULL;
-       struct ieee80211_if_ap *ap = NULL;
-       struct ieee80211_rate *rate;
-       struct rate_control_extra extra;
-       u8 *b_head, *b_tail;
-       int bh_len, bt_len;
-
-       bdev = dev_get_by_index(if_id);
-       if (bdev) {
-               sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-               ap = &sdata->u.ap;
-               dev_put(bdev);
-       }
-
-       if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
-           !ap->beacon_head) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "no beacon data avail for idx=%d "
-                              "(%s)\n", if_id, bdev ? bdev->name : "N/A");
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-               return NULL;
-       }
-
-       /* Assume we are generating the normal beacon locally */
-       b_head = ap->beacon_head;
-       b_tail = ap->beacon_tail;
-       bh_len = ap->beacon_head_len;
-       bt_len = ap->beacon_tail_len;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-               bh_len + bt_len + 256 /* maximum TIM len */);
-       if (!skb)
-               return NULL;
-
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-       memcpy(skb_put(skb, bh_len), b_head, bh_len);
-
-       ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
-
-       ieee80211_beacon_add_tim(local, ap, skb);
-
-       if (b_tail) {
-               memcpy(skb_put(skb, bt_len), b_tail, bt_len);
-       }
-
-       if (control) {
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = local->oper_hw_mode;
-
-               rate = rate_control_get_rate(local, local->mdev, skb, &extra);
-               if (!rate) {
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-                                      "found\n", local->mdev->name);
-                       }
-                       dev_kfree_skb(skb);
-                       return NULL;
-               }
-
-               control->tx_rate = (local->short_preamble &&
-                                   (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
-               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-               control->power_level = local->hw.conf.power_level;
-               control->flags |= IEEE80211_TXCTL_NO_ACK;
-               control->retry_limit = 1;
-               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
-       }
-
-       ap->num_beacons++;
-       return skb;
-}
-EXPORT_SYMBOL(ieee80211_beacon_get);
-
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
-                             size_t frame_len,
-                             const struct ieee80211_tx_control *frame_txctl)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_rate *rate;
-       int short_preamble = local->short_preamble;
-       int erp;
-       u16 dur;
-
-       rate = frame_txctl->rts_rate;
-       erp = !!(rate->flags & IEEE80211_RATE_ERP);
-
-       /* CTS duration */
-       dur = ieee80211_frame_duration(local, 10, rate->rate,
-                                      erp, short_preamble);
-       /* Data frame duration */
-       dur += ieee80211_frame_duration(local, frame_len, rate->rate,
-                                       erp, short_preamble);
-       /* ACK duration */
-       dur += ieee80211_frame_duration(local, 10, rate->rate,
-                                       erp, short_preamble);
-
-       return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_rts_duration);
-
-
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
-                                   size_t frame_len,
-                                   const struct ieee80211_tx_control *frame_txctl)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_rate *rate;
-       int short_preamble = local->short_preamble;
-       int erp;
-       u16 dur;
-
-       rate = frame_txctl->rts_rate;
-       erp = !!(rate->flags & IEEE80211_RATE_ERP);
-
-       /* Data frame duration */
-       dur = ieee80211_frame_duration(local, frame_len, rate->rate,
-                                      erp, short_preamble);
-       if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
-               /* ACK duration */
-               dur += ieee80211_frame_duration(local, 10, rate->rate,
-                                               erp, short_preamble);
-       }
-
-       return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_ctstoself_duration);
-
-void ieee80211_rts_get(struct ieee80211_hw *hw,
-                      const void *frame, size_t frame_len,
-                      const struct ieee80211_tx_control *frame_txctl,
-                      struct ieee80211_rts *rts)
-{
-       const struct ieee80211_hdr *hdr = frame;
-       u16 fctl;
-
-       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
-       rts->frame_control = cpu_to_le16(fctl);
-       rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl);
-       memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
-       memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
-}
-EXPORT_SYMBOL(ieee80211_rts_get);
-
-void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
-                            const void *frame, size_t frame_len,
-                            const struct ieee80211_tx_control *frame_txctl,
-                            struct ieee80211_cts *cts)
-{
-       const struct ieee80211_hdr *hdr = frame;
-       u16 fctl;
-
-       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
-       cts->frame_control = cpu_to_le16(fctl);
-       cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl);
-       memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
-}
-EXPORT_SYMBOL(ieee80211_ctstoself_get);
-
-struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
-                         struct ieee80211_tx_control *control)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct sk_buff *skb;
-       struct sta_info *sta;
-       ieee80211_tx_handler *handler;
-       struct ieee80211_txrx_data tx;
-       ieee80211_txrx_result res = TXRX_DROP;
-       struct net_device *bdev;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_ap *bss = NULL;
-
-       bdev = dev_get_by_index(if_id);
-       if (bdev) {
-               sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-               bss = &sdata->u.ap;
-               dev_put(bdev);
-       }
-       if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
-               return NULL;
-
-       if (bss->dtim_count != 0)
-               return NULL; /* send buffered bc/mc only after DTIM beacon */
-       memset(control, 0, sizeof(*control));
-       while (1) {
-               skb = skb_dequeue(&bss->ps_bc_buf);
-               if (!skb)
-                       return NULL;
-               local->total_ps_buffered--;
-
-               if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
-                       struct ieee80211_hdr *hdr =
-                               (struct ieee80211_hdr *) skb->data;
-                       /* more buffered multicast/broadcast frames ==> set
-                        * MoreData flag in IEEE 802.11 header to inform PS
-                        * STAs */
-                       hdr->frame_control |=
-                               cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-               }
-
-               if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0)
-                       break;
-               dev_kfree_skb_any(skb);
-       }
-       sta = tx.sta;
-       tx.u.tx.ps_buffered = 1;
-
-       for (handler = local->tx_handlers; *handler != NULL; handler++) {
-               res = (*handler)(&tx);
-               if (res == TXRX_DROP || res == TXRX_QUEUED)
-                       break;
-       }
-       dev_put(tx.dev);
-       skb = tx.skb; /* handlers are allowed to change skb */
-
-       if (res == TXRX_DROP) {
-               I802_DEBUG_INC(local->tx_handlers_drop);
-               dev_kfree_skb(skb);
-               skb = NULL;
-       } else if (res == TXRX_QUEUED) {
-               I802_DEBUG_INC(local->tx_handlers_queued);
-               skb = NULL;
-       }
-
-       if (sta)
-               sta_info_put(sta);
-
-       return skb;
-}
-EXPORT_SYMBOL(ieee80211_get_buffered_bc);
-
-static int __ieee80211_if_config(struct net_device *dev,
-                                struct sk_buff *beacon,
-                                struct ieee80211_tx_control *control)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_if_conf conf;
-       static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-       if (!local->ops->config_interface || !netif_running(dev))
-               return 0;
-
-       memset(&conf, 0, sizeof(conf));
-       conf.type = sdata->type;
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               if (local->sta_scanning &&
-                   local->scan_dev == dev)
-                       conf.bssid = scan_bssid;
-               else
-                       conf.bssid = sdata->u.sta.bssid;
-               conf.ssid = sdata->u.sta.ssid;
-               conf.ssid_len = sdata->u.sta.ssid_len;
-               conf.generic_elem = sdata->u.sta.extra_ie;
-               conf.generic_elem_len = sdata->u.sta.extra_ie_len;
-       } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
-               conf.ssid = sdata->u.ap.ssid;
-               conf.ssid_len = sdata->u.ap.ssid_len;
-               conf.generic_elem = sdata->u.ap.generic_elem;
-               conf.generic_elem_len = sdata->u.ap.generic_elem_len;
-               conf.beacon = beacon;
-               conf.beacon_control = control;
-       }
-       return local->ops->config_interface(local_to_hw(local),
-                                          dev->ifindex, &conf);
-}
-
-int ieee80211_if_config(struct net_device *dev)
-{
-       return __ieee80211_if_config(dev, NULL, NULL);
-}
-
-int ieee80211_if_config_beacon(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_control control;
-       struct sk_buff *skb;
-
-       if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-               return 0;
-       skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
-       if (!skb)
-               return -ENOMEM;
-       return __ieee80211_if_config(dev, skb, &control);
-}
-
-int ieee80211_hw_config(struct ieee80211_local *local)
-{
-       struct ieee80211_hw_mode *mode;
-       struct ieee80211_channel *chan;
-       int ret = 0;
-
-       if (local->sta_scanning) {
-               chan = local->scan_channel;
-               mode = local->scan_hw_mode;
-       } else {
-               chan = local->oper_channel;
-               mode = local->oper_hw_mode;
-       }
-
-       local->hw.conf.channel = chan->chan;
-       local->hw.conf.channel_val = chan->val;
-       local->hw.conf.power_level = chan->power_level;
-       local->hw.conf.freq = chan->freq;
-       local->hw.conf.phymode = mode->mode;
-       local->hw.conf.antenna_max = chan->antenna_max;
-       local->hw.conf.chan = chan;
-       local->hw.conf.mode = mode;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
-              "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
-              local->hw.conf.phymode);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-
-       if (local->ops->config)
-               ret = local->ops->config(local_to_hw(local), &local->hw.conf);
-
-       return ret;
-}
-
-
-static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
-{
-       /* FIX: what would be proper limits for MTU?
-        * This interface uses 802.3 frames. */
-       if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
-               printk(KERN_WARNING "%s: invalid MTU %d\n",
-                      dev->name, new_mtu);
-               return -EINVAL;
-       }
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-
-static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
-{
-       /* FIX: what would be proper limits for MTU?
-        * This interface uses 802.11 frames. */
-       if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
-               printk(KERN_WARNING "%s: invalid MTU %d\n",
-                      dev->name, new_mtu);
-               return -EINVAL;
-       }
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-enum netif_tx_lock_class {
-       TX_LOCK_NORMAL,
-       TX_LOCK_MASTER,
-};
-
-static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
-{
-       spin_lock_nested(&dev->_xmit_lock, subclass);
-       dev->xmit_lock_owner = smp_processor_id();
-}
-
-static void ieee80211_set_multicast_list(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       unsigned short flags;
-
-       netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
-       if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
-               if (sdata->allmulti) {
-                       sdata->allmulti = 0;
-                       local->iff_allmultis--;
-               } else {
-                       sdata->allmulti = 1;
-                       local->iff_allmultis++;
-               }
-       }
-       if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
-               if (sdata->promisc) {
-                       sdata->promisc = 0;
-                       local->iff_promiscs--;
-               } else {
-                       sdata->promisc = 1;
-                       local->iff_promiscs++;
-               }
-       }
-       if (dev->mc_count != sdata->mc_count) {
-               local->mc_count = local->mc_count - sdata->mc_count +
-                                 dev->mc_count;
-               sdata->mc_count = dev->mc_count;
-       }
-       if (local->ops->set_multicast_list) {
-               flags = local->mdev->flags;
-               if (local->iff_allmultis)
-                       flags |= IFF_ALLMULTI;
-               if (local->iff_promiscs)
-                       flags |= IFF_PROMISC;
-               read_lock(&local->sub_if_lock);
-               local->ops->set_multicast_list(local_to_hw(local), flags,
-                                             local->mc_count);
-               read_unlock(&local->sub_if_lock);
-       }
-       netif_tx_unlock(local->mdev);
-}
-
-struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
-                                              struct dev_mc_list *prev,
-                                              void **ptr)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata = *ptr;
-       struct dev_mc_list *mc;
-
-       if (!prev) {
-               WARN_ON(sdata);
-               sdata = NULL;
-       }
-       if (!prev || !prev->next) {
-               if (sdata)
-                       sdata = list_entry(sdata->list.next,
-                                          struct ieee80211_sub_if_data, list);
-               else
-                       sdata = list_entry(local->sub_if_list.next,
-                                          struct ieee80211_sub_if_data, list);
-               if (&sdata->list != &local->sub_if_list)
-                       mc = sdata->dev->mc_list;
-               else
-                       mc = NULL;
-       } else
-               mc = prev->next;
-
-       *ptr = sdata;
-       return mc;
-}
-EXPORT_SYMBOL(ieee80211_get_mc_list_item);
-
-static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata;
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       return &(sdata->stats);
-}
-
-static void ieee80211_if_shutdown(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       ASSERT_RTNL();
-       switch (sdata->type) {
-       case IEEE80211_IF_TYPE_STA:
-       case IEEE80211_IF_TYPE_IBSS:
-               sdata->u.sta.state = IEEE80211_DISABLED;
-               del_timer_sync(&sdata->u.sta.timer);
-               del_timer_sync(&sdata->u.sta.admit_timer);
-               skb_queue_purge(&sdata->u.sta.skb_queue);
-               if (!local->ops->hw_scan &&
-                   local->scan_dev == sdata->dev) {
-                       local->sta_scanning = 0;
-                       cancel_delayed_work(&local->scan_work);
-               }
-               flush_workqueue(local->hw.workqueue);
-               break;
-       }
-}
-
-static inline int identical_mac_addr_allowed(int type1, int type2)
-{
-       return (type1 == IEEE80211_IF_TYPE_MNTR ||
-               type2 == IEEE80211_IF_TYPE_MNTR ||
-               (type1 == IEEE80211_IF_TYPE_AP &&
-                type2 == IEEE80211_IF_TYPE_WDS) ||
-               (type1 == IEEE80211_IF_TYPE_WDS &&
-                (type2 == IEEE80211_IF_TYPE_WDS ||
-                 type2 == IEEE80211_IF_TYPE_AP)) ||
-               (type1 == IEEE80211_IF_TYPE_AP &&
-                type2 == IEEE80211_IF_TYPE_VLAN) ||
-               (type1 == IEEE80211_IF_TYPE_VLAN &&
-                (type2 == IEEE80211_IF_TYPE_AP ||
-                 type2 == IEEE80211_IF_TYPE_VLAN)));
-}
-
-static int ieee80211_master_open(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       int res = -EOPNOTSUPP;
-
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
-               if (sdata->dev != dev && netif_running(sdata->dev)) {
-                       res = 0;
-                       break;
-               }
-       }
-       read_unlock(&local->sub_if_lock);
-       return res;
-}
-
-static int ieee80211_master_stop(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list)
-               if (sdata->dev != dev && netif_running(sdata->dev))
-                       dev_close(sdata->dev);
-       read_unlock(&local->sub_if_lock);
-
-       return 0;
-}
-
-static int ieee80211_mgmt_open(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       if (!netif_running(local->mdev))
-               return -EOPNOTSUPP;
-       return 0;
-}
-
-static int ieee80211_mgmt_stop(struct net_device *dev)
-{
-       return 0;
-}
-
-/* Check if running monitor interfaces should go to a "soft monitor" mode
- * and switch them if necessary. */
-static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
-{
-       struct ieee80211_if_init_conf conf;
-
-       if (local->open_count && local->open_count == local->monitors &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-           local->ops->remove_interface) {
-               conf.if_id = -1;
-               conf.type = IEEE80211_IF_TYPE_MNTR;
-               conf.mac_addr = NULL;
-               local->ops->remove_interface(local_to_hw(local), &conf);
-       }
-}
-
-/* Check if running monitor interfaces should go to a "hard monitor" mode
- * and switch them if necessary. */
-static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
-{
-       struct ieee80211_if_init_conf conf;
-
-       if (local->open_count && local->open_count == local->monitors &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-           local->ops->add_interface) {
-               conf.if_id = -1;
-               conf.type = IEEE80211_IF_TYPE_MNTR;
-               conf.mac_addr = NULL;
-               local->ops->add_interface(local_to_hw(local), &conf);
-       }
-}
-
-static int ieee80211_open(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata, *nsdata;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_if_init_conf conf;
-       int res;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(nsdata, &local->sub_if_list, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
-                   compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
-                   !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
-                       read_unlock(&local->sub_if_lock);
-                       return -ENOTUNIQ;
-               }
-       }
-       read_unlock(&local->sub_if_lock);
-
-       if (sdata->type == IEEE80211_IF_TYPE_WDS &&
-           is_zero_ether_addr(sdata->u.wds.remote_addr))
-               return -ENOLINK;
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-               /* run the interface in a "soft monitor" mode */
-               local->monitors++;
-               local->open_count++;
-               local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-               return 0;
-       }
-       ieee80211_start_soft_monitor(local);
-
-       if (local->ops->add_interface) {
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
-               conf.mac_addr = dev->dev_addr;
-               res = local->ops->add_interface(local_to_hw(local), &conf);
-               if (res) {
-                       if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-                               ieee80211_start_hard_monitor(local);
-                       return res;
-               }
-       } else {
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
-                       return -EOPNOTSUPP;
-               if (local->open_count > 0)
-                       return -ENOBUFS;
-       }
-
-       if (local->open_count == 0) {
-               res = 0;
-               tasklet_enable(&local->tx_pending_tasklet);
-               tasklet_enable(&local->tasklet);
-               if (local->ops->open)
-                       res = local->ops->open(local_to_hw(local));
-               if (res == 0) {
-                       res = dev_open(local->mdev);
-                       if (res) {
-                               if (local->ops->stop)
-                                       local->ops->stop(local_to_hw(local));
-                       } else {
-                               res = ieee80211_hw_config(local);
-                               if (res && local->ops->stop)
-                                       local->ops->stop(local_to_hw(local));
-                               else if (!res && local->apdev)
-                                       dev_open(local->apdev);
-                       }
-               }
-               if (res) {
-                       if (local->ops->remove_interface)
-                               local->ops->remove_interface(local_to_hw(local),
-                                                           &conf);
-                       return res;
-               }
-       }
-       local->open_count++;
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-               local->monitors++;
-               local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-       } else
-               ieee80211_if_config(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_STA &&
-           !local->user_space_mlme)
-               netif_carrier_off(dev);
-       else
-               netif_carrier_on(dev);
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-
-static int ieee80211_stop(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
-           local->open_count > 1 &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-               /* remove "soft monitor" interface */
-               local->open_count--;
-               local->monitors--;
-               if (!local->monitors)
-                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-               return 0;
-       }
-
-       netif_stop_queue(dev);
-       ieee80211_if_shutdown(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-               local->monitors--;
-               if (!local->monitors)
-                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-       }
-
-       local->open_count--;
-       if (local->open_count == 0) {
-               if (netif_running(local->mdev))
-                       dev_close(local->mdev);
-               if (local->apdev)
-                       dev_close(local->apdev);
-               if (local->ops->stop)
-                       local->ops->stop(local_to_hw(local));
-               tasklet_disable(&local->tx_pending_tasklet);
-               tasklet_disable(&local->tasklet);
-       }
-       if (local->ops->remove_interface) {
-               struct ieee80211_if_init_conf conf;
-
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
-               conf.mac_addr = dev->dev_addr;
-               local->ops->remove_interface(local_to_hw(local), &conf);
-       }
-
-       ieee80211_start_hard_monitor(local);
-
-       return 0;
-}
-
-
-static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
-{
-       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-       return ETH_ALEN;
-}
-
-static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
-{
-       return compare_ether_addr(raddr, addr) == 0 ||
-              is_broadcast_ether_addr(raddr);
-}
-
-
-inline static unsigned int calc_pad_len(unsigned int len)
-{
-       return ((4 - len) & 0x3);
-}
-
-static ieee80211_txrx_result
-ieee80211_rx_h_data_agg(struct ieee80211_txrx_data *rx)
-{
-       struct net_device *dev = rx->dev;
-       struct ieee80211_local *local = rx->local;
-       u16 fc, hdrlen, ethertype;
-       u8 *payload;
-       struct sk_buff *skb = rx->skb, *skb2, *frame;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       const struct ethhdr* eth;
-       int remaining;
-
-       fc = rx->fc;
-       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-               return TXRX_CONTINUE;
-
-       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-               return TXRX_DROP;
-
-       if (!rx->u.rx.is_agg_frame)
-               return TXRX_CONTINUE;
-
-       hdrlen = ieee80211_get_hdrlen(fc);
-
-       payload = skb->data + hdrlen;
-
-       if (unlikely((skb->len - hdrlen) < 8)) {
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "%s: RX too short data frame "
-                              "payload\n", dev->name);
-               return TXRX_DROP;
-       }
-
-       ethertype = (payload[6] << 8) | payload[7];
-
-       if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-                   ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                  compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
-               /* remove RFC1042 or Bridge-Tunnel encapsulation and
-               * replace EtherType */
-               eth = (struct ethhdr*) (skb->data + hdrlen + 6);
-               remaining = skb->len - (hdrlen + 6);
-       } else {
-               eth = (struct ethhdr*) (skb->data + hdrlen);
-               remaining = skb->len - hdrlen;
-       }
-
-       while ((u8*)eth < skb->data + skb->len) {
-               u8 padding;
-               unsigned int subframe_len = sizeof(struct ethhdr) +
-                                                  ntohs(eth->h_proto);
-
-               padding = calc_pad_len(subframe_len);
-               /* the last MSDU has no padding */
-               if (subframe_len > remaining)
-                       return TXRX_DROP;
-
-               frame = dev_alloc_skb(local->hw.extra_tx_headroom +
-                                     subframe_len);
-
-               if (frame == NULL)
-                       return TXRX_DROP;
-
-               memcpy(skb_put(frame, subframe_len), (u8*)eth, subframe_len);
-               skb_set_mac_header(frame, 0);
-               skb2 = NULL;
-
-               sdata->stats.rx_packets++;
-               sdata->stats.rx_bytes += frame->len;
-
-               if (local->bridge_packets &&
-                   (sdata->type == IEEE80211_IF_TYPE_AP ||
-                    sdata->type == IEEE80211_IF_TYPE_VLAN) &&
-                    rx->u.rx.ra_match) {
-                       if (is_multicast_ether_addr(frame->data)) {
-                               /* send multicast frames both to higher layers
-                               * in local net stack and back to the wireless
-                               * media */
-                               skb2 = skb_copy(frame, GFP_ATOMIC);
-                               if (!skb2)
-                                       printk(KERN_DEBUG "%s: failed to clone"
-                                              " multicast frame\n", dev->name);
-                       } else {
-                               struct sta_info *dsta;
-
-                               dsta = sta_info_get(local, frame->data);
-                               if (dsta && !dsta->dev)
-                                       printk(KERN_DEBUG "Station with null "
-                                              "dev structure!\n");
-                               else if (dsta && dsta->dev == dev) {
-                                       /* Destination station is associated
-                                       * to this AP, so send the frame
-                                       * directly to it and do not pass
-                                       * the frame to local net stack.
-                                       */
-                                       skb2 = frame;
-                                       frame = NULL;
-                               }
-                               if (dsta)
-                                       sta_info_put(dsta);
-                       }
-               }
-               if (frame) {
-                       /* deliver to local stack */
-                       frame->protocol = eth_type_trans(frame, dev);
-                       frame->priority = skb->priority;
-                       frame->dev = dev;
-                       netif_rx(frame);
-               }
-
-               if (skb2) {
-                       /* send to wireless media */
-                       skb2->protocol = __constant_htons(ETH_P_802_3);
-                       skb_set_network_header(skb2, 0);
-                       skb_set_mac_header(skb2, 0);
-                       skb2->priority = skb->priority;
-                       skb2->dev = dev;
-                       dev_queue_xmit(skb2);
-               }
-
-               eth = (struct ethhdr*)((u8*)eth + subframe_len + padding);
-
-               remaining -= (subframe_len + padding);
-       }
-
-       dev_kfree_skb(skb);
-       return TXRX_QUEUED;
-}
-
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
-{
-       struct net_device *dev = rx->dev;
-       struct ieee80211_local *local = rx->local;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
-       u16 fc, hdrlen, ethertype;
-       u8 *payload;
-       u8 dst[ETH_ALEN];
-       u8 src[ETH_ALEN];
-       struct sk_buff *skb = rx->skb, *skb2;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       fc = rx->fc;
-       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-               return TXRX_CONTINUE;
-
-       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-               return TXRX_DROP;
-
-       hdrlen = ieee80211_get_hdrlen(fc);
-
-       /* convert IEEE 802.11 header + possible LLC headers into Ethernet
-        * header
-        * IEEE 802.11 address fields:
-        * ToDS FromDS Addr1 Addr2 Addr3 Addr4
-        *   0     0   DA    SA    BSSID n/a
-        *   0     1   DA    BSSID SA    n/a
-        *   1     0   BSSID SA    DA    n/a
-        *   1     1   RA    TA    DA    SA
-        */
-
-       switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-       case IEEE80211_FCTL_TODS:
-               /* BSSID SA DA */
-               memcpy(dst, hdr->addr3, ETH_ALEN);
-               memcpy(src, hdr->addr2, ETH_ALEN);
-
-               if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
-                            sdata->type != IEEE80211_IF_TYPE_VLAN)) {
-                       printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID="
-                              MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n",
-                              dev->name, MAC_ARG(hdr->addr1),
-                              MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3));
-                       return TXRX_DROP;
-               }
-               break;
-       case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-               /* RA TA DA SA */
-               memcpy(dst, hdr->addr3, ETH_ALEN);
-               memcpy(src, hdr->addr4, ETH_ALEN);
-
-               if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
-                       printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA="
-                              MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA="
-                              MAC_FMT ")\n",
-                              rx->dev->name, MAC_ARG(hdr->addr1),
-                              MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3),
-                              MAC_ARG(hdr->addr4));
-                       return TXRX_DROP;
-               }
-               break;
-       case IEEE80211_FCTL_FROMDS:
-               /* DA BSSID SA */
-               memcpy(dst, hdr->addr1, ETH_ALEN);
-               memcpy(src, hdr->addr3, ETH_ALEN);
-
-               if (sdata->type != IEEE80211_IF_TYPE_STA) {
-                       return TXRX_DROP;
-               }
-               break;
-       case 0:
-               /* DA SA BSSID */
-               memcpy(dst, hdr->addr1, ETH_ALEN);
-               memcpy(src, hdr->addr2, ETH_ALEN);
-
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
-                                      MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
-                                      ")\n",
-                                      dev->name, MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3));
-                       }
-                       return TXRX_DROP;
-               }
-               break;
-       }
-
-       payload = skb->data + hdrlen;
-
-       if (unlikely(skb->len - hdrlen < 8)) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: RX too short data frame "
-                              "payload\n", dev->name);
-               }
-               return TXRX_DROP;
-       }
-
-       ethertype = (payload[6] << 8) | payload[7];
-
-       if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-                   ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                  compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
-               /* remove RFC1042 or Bridge-Tunnel encapsulation and
-                * replace EtherType */
-               skb_pull(skb, hdrlen + 6);
-               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-       } else {
-               struct ethhdr *ehdr;
-               __be16 len;
-               skb_pull(skb, hdrlen);
-               len = htons(skb->len);
-               ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-               memcpy(ehdr->h_dest, dst, ETH_ALEN);
-               memcpy(ehdr->h_source, src, ETH_ALEN);
-               ehdr->h_proto = len;
-       }
-       skb->dev = dev;
-
-       skb2 = NULL;
-
-       sdata->stats.rx_packets++;
-       sdata->stats.rx_bytes += skb->len;
-
-       if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-           || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) {
-               if (is_multicast_ether_addr(skb->data)) {
-                       /* send multicast frames both to higher layers in
-                        * local net stack and back to the wireless media */
-                       skb2 = skb_copy(skb, GFP_ATOMIC);
-                       if (!skb2)
-                               printk(KERN_DEBUG "%s: failed to clone "
-                                      "multicast frame\n", dev->name);
-               } else {
-                       struct sta_info *dsta;
-                       dsta = sta_info_get(local, skb->data);
-                       if (dsta && !dsta->dev) {
-                               printk(KERN_DEBUG "Station with null dev "
-                                      "structure!\n");
-                       } else if (dsta && dsta->dev == dev) {
-                               /* Destination station is associated to this
-                                * AP, so send the frame directly to it and
-                                * do not pass the frame to local net stack.
-                                */
-                               skb2 = skb;
-                               skb = NULL;
-                       }
-                       if (dsta)
-                               sta_info_put(dsta);
-               }
-       }
-
-       if (skb) {
-               /* deliver to local stack */
-               skb->protocol = eth_type_trans(skb, dev);
-               memset(skb->cb, 0, sizeof(skb->cb));
-               netif_rx(skb);
-       }
-
-       if (skb2) {
-               /* send to wireless media */
-               skb2->protocol = __constant_htons(ETH_P_802_3);
-               skb_set_network_header(skb2, 0);
-               skb_set_mac_header(skb2, 0);
-               dev_queue_xmit(skb2);
-       }
-
-       return TXRX_QUEUED;
-}
-
-
-static struct ieee80211_rate *
-ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
-{
-       struct ieee80211_hw_mode *mode;
-       int r;
-
-       list_for_each_entry(mode, &local->modes_list, list) {
-               if (mode->mode != phymode)
-                       continue;
-               for (r = 0; r < mode->num_rates; r++) {
-                       struct ieee80211_rate *rate = &mode->rates[r];
-                       if (rate->val == hw_rate ||
-                           (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
-                            rate->val2 == hw_rate))
-                               return rate;
-               }
-       }
-
-       return NULL;
-}
-
-static void
-ieee80211_fill_frame_info(struct ieee80211_local *local,
-                         struct ieee80211_frame_info *fi,
-                         struct ieee80211_rx_status *status)
-{
-       if (status) {
-               struct timespec ts;
-               struct ieee80211_rate *rate;
-
-               jiffies_to_timespec(jiffies, &ts);
-               fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
-                                          ts.tv_nsec / 1000);
-               fi->mactime = cpu_to_be64(status->mactime);
-               switch (status->phymode) {
-               case MODE_IEEE80211A:
-                       fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
-                       break;
-               case MODE_IEEE80211B:
-                       fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
-                       break;
-               case MODE_IEEE80211G:
-                       fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
-                       break;
-               case MODE_ATHEROS_TURBO:
-                       fi->phytype =
-                               htonl(ieee80211_phytype_dsss_dot11_turbo);
-                       break;
-               default:
-                       fi->phytype = htonl(0xAAAAAAAA);
-                       break;
-               }
-               fi->channel = htonl(status->channel);
-               rate = ieee80211_get_rate(local, status->phymode,
-                                         status->rate);
-               if (rate) {
-                       fi->datarate = htonl(rate->rate);
-                       if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
-                               if (status->rate == rate->val)
-                                       fi->preamble = htonl(2); /* long */
-                               else if (status->rate == rate->val2)
-                                       fi->preamble = htonl(1); /* short */
-                       } else
-                               fi->preamble = htonl(0);
-               } else {
-                       fi->datarate = htonl(0);
-                       fi->preamble = htonl(0);
-               }
-
-               fi->antenna = htonl(status->antenna);
-               fi->priority = htonl(0xffffffff); /* no clue */
-               fi->ssi_type = htonl(ieee80211_ssi_raw);
-               fi->ssi_signal = htonl(status->ssi);
-               fi->ssi_noise = 0x00000000;
-               fi->encoding = 0;
-       } else {
-               /* clear everything because we really don't know.
-                * the msg_type field isn't present on monitor frames
-                * so we don't know whether it will be present or not,
-                * but it's ok to not clear it since it'll be assigned
-                * anyway */
-               memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
-
-               fi->ssi_type = htonl(ieee80211_ssi_none);
-       }
-       fi->version = htonl(IEEE80211_FI_VERSION);
-       fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
-}
-
-/* this routine is actually not just for this, but also
- * for pushing fake 'management' frames into userspace.
- * it shall be replaced by a netlink-based system. */
-void
-ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
-                 struct ieee80211_rx_status *status, u32 msg_type)
-{
-       struct ieee80211_frame_info *fi;
-       const size_t hlen = sizeof(struct ieee80211_frame_info);
-       struct ieee80211_sub_if_data *sdata;
-
-       skb->dev = local->apdev;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev);
-
-       if (skb_headroom(skb) < hlen) {
-               I802_DEBUG_INC(local->rx_expand_skb_head);
-               if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
-                       dev_kfree_skb(skb);
-                       return;
-               }
-       }
-
-       fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
-
-       ieee80211_fill_frame_info(local, fi, status);
-       fi->msg_type = htonl(msg_type);
-
-       sdata->stats.rx_packets++;
-       sdata->stats.rx_bytes += skb->len;
-
-       skb_set_mac_header(skb, 0);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = htons(ETH_P_802_2);
-       memset(skb->cb, 0, sizeof(skb->cb));
-       netif_rx(skb);
-}
-
-static void
-ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
-                    struct ieee80211_rx_status *status)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_rate *rate;
-       struct ieee80211_rtap_hdr {
-               struct ieee80211_radiotap_header hdr;
-               u8 flags;
-               u8 rate;
-               __le16 chan_freq;
-               __le16 chan_flags;
-               u8 antsignal;
-       } __attribute__ ((packed)) *rthdr;
-
-       skb->dev = dev;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (status->flag & RX_FLAG_RADIOTAP)
-               goto out;
-
-       if (skb_headroom(skb) < sizeof(*rthdr)) {
-               I802_DEBUG_INC(local->rx_expand_skb_head);
-               if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
-                       dev_kfree_skb(skb);
-                       return;
-               }
-       }
-
-       rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
-       memset(rthdr, 0, sizeof(*rthdr));
-       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
-       rthdr->hdr.it_present =
-               cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_RATE) |
-                           (1 << IEEE80211_RADIOTAP_CHANNEL) |
-                           (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
-       rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
-                      IEEE80211_RADIOTAP_F_FCS : 0;
-       rate = ieee80211_get_rate(local, status->phymode, status->rate);
-       if (rate)
-               rthdr->rate = rate->rate / 5;
-       rthdr->chan_freq = cpu_to_le16(status->freq);
-       rthdr->chan_flags =
-               status->phymode == MODE_IEEE80211A ?
-               cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
-               cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
-       rthdr->antsignal = status->ssi;
-
- out:
-       sdata->stats.rx_packets++;
-       sdata->stats.rx_bytes += skb->len;
-
-       skb_set_mac_header(skb, 0);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = htons(ETH_P_802_2);
-       memset(skb->cb, 0, sizeof(skb->cb));
-       netif_rx(skb);
-}
-
-int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
-                          int radar, int radar_type)
-{
-       struct sk_buff *skb;
-       struct ieee80211_radar_info *msg;
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       if (!local->apdev)
-               return 0;
-
-       skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
-                           sizeof(struct ieee80211_radar_info));
-
-       if (!skb)
-               return -ENOMEM;
-       skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-
-       msg = (struct ieee80211_radar_info *)
-               skb_put(skb, sizeof(struct ieee80211_radar_info));
-       msg->channel = channel;
-       msg->radar = radar;
-       msg->radar_type = radar_type;
-
-       ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar);
-       return 0;
-}
-EXPORT_SYMBOL(ieee80211_radar_status);
-
-int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address,
-                             u16 aid)
-{
-       struct sk_buff *skb;
-       struct ieee80211_msg_set_aid_for_sta *msg;
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       /* unlikely because if this event only happens for APs,
-        * which require an open ap device. */
-       if (unlikely(!local->apdev))
-               return 0;
-
-       skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
-                           sizeof(struct ieee80211_msg_set_aid_for_sta));
-
-       if (!skb)
-               return -ENOMEM;
-       skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-
-       msg = (struct ieee80211_msg_set_aid_for_sta *)
-               skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta));
-       memcpy(msg->sta_address, peer_address, ETH_ALEN);
-       msg->aid = aid;
-
-       ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta);
-       return 0;
-}
-EXPORT_SYMBOL(ieee80211_set_aid_for_sta);
-
-static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
-{
-       struct ieee80211_sub_if_data *sdata;
-       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-
-       if (sdata->bss)
-               atomic_inc(&sdata->bss->num_sta_ps);
-       sta->flags |= WLAN_STA_PS;
-       sta->pspoll = 0;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
-              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-}
-
-
-static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sk_buff *skb;
-       int sent = 0;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_packet_data *pkt_data;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-       if (sdata->bss)
-               atomic_dec(&sdata->bss->num_sta_ps);
-       sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
-       sta->pspoll = 0;
-       if (!skb_queue_empty(&sta->ps_tx_buf)) {
-               if (local->ops->set_tim)
-                       local->ops->set_tim(local_to_hw(local), sta->aid, 0);
-               if (sdata->bss)
-                       bss_tim_clear(local, sdata->bss, sta->aid);
-       }
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
-              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       /* Send all buffered frames to the station */
-       while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
-               sent++;
-               pkt_data->requeue = 1;
-               dev_queue_xmit(skb);
-       }
-       while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
-               local->total_ps_buffered--;
-               sent++;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
-                      "since STA not sleeping anymore\n", dev->name,
-                      MAC_ARG(sta->addr), sta->aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               pkt_data->requeue = 1;
-               dev_queue_xmit(skb);
-       }
-
-       return sent;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
-{
-       struct sk_buff *skb;
-       int no_pending_pkts;
-
-       if (likely(!rx->sta ||
-                  (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
-                  (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
-                  !rx->u.rx.ra_match))
-               return TXRX_CONTINUE;
-
-       skb = skb_dequeue(&rx->sta->tx_filtered);
-       if (!skb) {
-               skb = skb_dequeue(&rx->sta->ps_tx_buf);
-               if (skb)
-                       rx->local->total_ps_buffered--;
-       }
-       no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
-               skb_queue_empty(&rx->sta->ps_tx_buf);
-
-       if (skb) {
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) skb->data;
-
-               /* tell TX path to send one frame even though the STA may
-                * still remain is PS mode after this frame exchange */
-               rx->sta->pspoll = 1;
-
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
-                      "after %d)\n",
-                      MAC_ARG(rx->sta->addr), rx->sta->aid,
-                      skb_queue_len(&rx->sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
-               /* Use MoreData flag to indicate whether there are more
-                * buffered frames for this STA */
-               if (no_pending_pkts) {
-                       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-                       rx->sta->flags &= ~WLAN_STA_TIM;
-               } else
-                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-
-               dev_queue_xmit(skb);
-
-               if (no_pending_pkts) {
-                       if (rx->local->ops->set_tim)
-                               rx->local->ops->set_tim(local_to_hw(rx->local),
-                                                      rx->sta->aid, 0);
-                       if (rx->sdata->bss)
-                               bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
-               }
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       } else if (!rx->u.rx.sent_ps_buffered) {
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
-                      "though there is no buffered frames for it\n",
-                      rx->dev->name, MAC_ARG(rx->sta->addr));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
-       }
-
-       /* Free PS Poll skb here instead of returning TXRX_DROP that would
-        * count as an dropped frame. */
-       dev_kfree_skb(rx->skb);
-
-       return TXRX_QUEUED;
-}
-
-
-static inline struct ieee80211_fragment_entry *
-ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
-                        unsigned int frag, unsigned int seq, int rx_queue,
-                        struct sk_buff **skb)
-{
-       struct ieee80211_fragment_entry *entry;
-       int idx;
-
-       idx = sdata->fragment_next;
-       entry = &sdata->fragments[sdata->fragment_next++];
-       if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
-               sdata->fragment_next = 0;
-
-       if (!skb_queue_empty(&entry->skb_list)) {
-#ifdef CONFIG_MAC80211_DEBUG
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) entry->skb_list.next->data;
-               printk(KERN_DEBUG "%s: RX reassembly removed oldest "
-                      "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-                      "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
-                      sdata->dev->name, idx,
-                      jiffies - entry->first_frag_time, entry->seq,
-                      entry->last_frag, MAC_ARG(hdr->addr1),
-                      MAC_ARG(hdr->addr2));
-#endif /* CONFIG_MAC80211_DEBUG */
-               __skb_queue_purge(&entry->skb_list);
-       }
-
-       __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
-       *skb = NULL;
-       entry->first_frag_time = jiffies;
-       entry->seq = seq;
-       entry->rx_queue = rx_queue;
-       entry->last_frag = frag;
-       entry->ccmp = 0;
-       entry->extra_len = 0;
-
-       return entry;
-}
-
-
-static inline struct ieee80211_fragment_entry *
-ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
-                         u16 fc, unsigned int frag, unsigned int seq,
-                         int rx_queue, struct ieee80211_hdr *hdr)
-{
-       struct ieee80211_fragment_entry *entry;
-       int i, idx;
-
-       idx = sdata->fragment_next;
-       for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
-               struct ieee80211_hdr *f_hdr;
-               u16 f_fc;
-
-               idx--;
-               if (idx < 0)
-                       idx = IEEE80211_FRAGMENT_MAX - 1;
-
-               entry = &sdata->fragments[idx];
-               if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
-                   entry->rx_queue != rx_queue ||
-                   entry->last_frag + 1 != frag)
-                       continue;
-
-               f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
-               f_fc = le16_to_cpu(f_hdr->frame_control);
-
-               if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) ||
-                   compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
-                   compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
-                       continue;
-
-               if (entry->first_frag_time + 2 * HZ < jiffies) {
-                       __skb_queue_purge(&entry->skb_list);
-                       continue;
-               }
-               return entry;
-       }
-
-       return NULL;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
-{
-       struct ieee80211_hdr *hdr;
-       u16 sc;
-       unsigned int frag, seq;
-       struct ieee80211_fragment_entry *entry;
-       struct sk_buff *skb;
-
-       hdr = (struct ieee80211_hdr *) rx->skb->data;
-       sc = le16_to_cpu(hdr->seq_ctrl);
-       frag = sc & IEEE80211_SCTL_FRAG;
-
-       if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) ||
-                  (rx->skb)->len < 24 ||
-                  is_multicast_ether_addr(hdr->addr1))) {
-               /* not fragmented */
-               goto out;
-       }
-       I802_DEBUG_INC(rx->local->rx_handlers_fragments);
-
-       seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-
-       if (frag == 0) {
-               /* This is the first fragment of a new frame. */
-               entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
-                                                rx->u.rx.queue, &(rx->skb));
-               if (rx->key && rx->key->alg == ALG_CCMP &&
-                   (rx->fc & IEEE80211_FCTL_PROTECTED)) {
-                       /* Store CCMP PN so that we can verify that the next
-                        * fragment has a sequential PN value. */
-                       entry->ccmp = 1;
-                       memcpy(entry->last_pn,
-                              rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
-                              CCMP_PN_LEN);
-               }
-               return TXRX_QUEUED;
-       }
-
-       /* This is a fragment for a frame that should already be pending in
-        * fragment cache. Add this fragment to the end of the pending entry.
-        */
-       entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
-                                         rx->u.rx.queue, hdr);
-       if (!entry) {
-               I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-               return TXRX_DROP;
-       }
-
-       /* Verify that MPDUs within one MSDU have sequential PN values.
-        * (IEEE 802.11i, 8.3.3.4.5) */
-       if (entry->ccmp) {
-               int i;
-               u8 pn[CCMP_PN_LEN], *rpn;
-               if (!rx->key || rx->key->alg != ALG_CCMP)
-                       return TXRX_DROP;
-               memcpy(pn, entry->last_pn, CCMP_PN_LEN);
-               for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
-                       pn[i]++;
-                       if (pn[i])
-                               break;
-               }
-               rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
-               if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
-                       printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential"
-                              " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x "
-                              "(expected %02x%02x%02x%02x%02x%02x)\n",
-                              rx->dev->name, MAC_ARG(hdr->addr2),
-                              rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5],
-                              pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
-                       return TXRX_DROP;
-               }
-               memcpy(entry->last_pn, pn, CCMP_PN_LEN);
-       }
-
-       skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
-       __skb_queue_tail(&entry->skb_list, rx->skb);
-       entry->last_frag = frag;
-       entry->extra_len += rx->skb->len;
-       if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
-               rx->skb = NULL;
-               return TXRX_QUEUED;
-       }
-
-       rx->skb = __skb_dequeue(&entry->skb_list);
-       if (skb_tailroom(rx->skb) < entry->extra_len) {
-               I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
-               if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
-                                             GFP_ATOMIC))) {
-                       I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-                       __skb_queue_purge(&entry->skb_list);
-                       return TXRX_DROP;
-               }
-       }
-       while ((skb = __skb_dequeue(&entry->skb_list))) {
-               memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len);
-               dev_kfree_skb(skb);
-       }
-
-       /* Complete frame has been reassembled - process it now */
-       rx->fragmented = 1;
-
- out:
-       if (rx->sta)
-               rx->sta->rx_packets++;
-       if (is_multicast_ether_addr(hdr->addr1))
-               rx->local->dot11MulticastReceivedFrameCount++;
-       else
-               ieee80211_led_rx(rx->local);
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
-{
-       if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) {
-               ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status);
-               return TXRX_QUEUED;
-       }
-
-       if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP)
-               skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb));
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
-{
-       struct ieee80211_hdr *hdr;
-       int always_sta_key;
-       hdr = (struct ieee80211_hdr *) rx->skb->data;
-
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
-               if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
-                            rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
-                            hdr->seq_ctrl)) {
-                       if (rx->u.rx.ra_match) {
-                               rx->local->dot11FrameDuplicateCount++;
-                               rx->sta->num_duplicates++;
-                       }
-                       return TXRX_DROP;
-               } else
-                       rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
-       }
-
-       if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) &&
-           rx->skb->len > FCS_LEN)
-               skb_trim(rx->skb, rx->skb->len - FCS_LEN);
-
-       if (unlikely(rx->skb->len < 16)) {
-               I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
-               return TXRX_DROP;
-       }
-
-       if (!rx->u.rx.ra_match)
-               rx->skb->pkt_type = PACKET_OTHERHOST;
-       else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
-               rx->skb->pkt_type = PACKET_HOST;
-       else if (is_multicast_ether_addr(hdr->addr1)) {
-               if (is_broadcast_ether_addr(hdr->addr1))
-                       rx->skb->pkt_type = PACKET_BROADCAST;
-               else
-                       rx->skb->pkt_type = PACKET_MULTICAST;
-       } else
-               rx->skb->pkt_type = PACKET_OTHERHOST;
-
-       /* Drop disallowed frame classes based on STA auth/assoc state;
-        * IEEE 802.11, Chap 5.5.
-        *
-        * 80211.o does filtering only based on association state, i.e., it
-        * drops Class 3 frames from not associated stations. hostapd sends
-        * deauth/disassoc frames when needed. In addition, hostapd is
-        * responsible for filtering on both auth and assoc states.
-        */
-       if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
-                     ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
-                      (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
-                    rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
-                    (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
-               if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
-                    !(rx->fc & IEEE80211_FCTL_TODS) &&
-                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-                   || !rx->u.rx.ra_match) {
-                       /* Drop IBSS frames and frames for other hosts
-                        * silently. */
-                       return TXRX_DROP;
-               }
-
-               if (!rx->local->apdev)
-                       return TXRX_DROP;
-
-               ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-                                 ieee80211_msg_sta_not_assoc);
-               return TXRX_QUEUED;
-       }
-
-       if (rx->sdata->type == IEEE80211_IF_TYPE_STA)
-               always_sta_key = 0;
-       else
-               always_sta_key = 1;
-
-       if (rx->sta && rx->sta->key && always_sta_key) {
-               rx->key = rx->sta->key;
-       } else {
-               if (rx->sta && rx->sta->key)
-                       rx->key = rx->sta->key;
-               else
-                       rx->key = rx->sdata->default_key;
-
-               if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
-                   rx->fc & IEEE80211_FCTL_PROTECTED) {
-                       int keyidx = ieee80211_wep_get_keyidx(rx->skb);
-
-                       if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS &&
-                           (!rx->sta || !rx->sta->key || keyidx > 0))
-                               rx->key = rx->sdata->keys[keyidx];
-
-                       if (!rx->key) {
-                               if (!rx->u.rx.ra_match)
-                                       return TXRX_DROP;
-                               printk(KERN_DEBUG "%s: RX WEP frame with "
-                                      "unknown keyidx %d (A1=" MAC_FMT " A2="
-                                      MAC_FMT " A3=" MAC_FMT ")\n",
-                                      rx->dev->name, keyidx,
-                                      MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3));
-                               if (!rx->local->apdev)
-                                       return TXRX_DROP;
-                               ieee80211_rx_mgmt(
-                                       rx->local, rx->skb, rx->u.rx.status,
-                                       ieee80211_msg_wep_frame_unknown_key);
-                               return TXRX_QUEUED;
-                       }
-               }
-       }
-
-       if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) {
-               rx->key->tx_rx_count++;
-               if (unlikely(rx->local->key_tx_rx_threshold &&
-                            rx->key->tx_rx_count >
-                            rx->local->key_tx_rx_threshold)) {
-                       ieee80211_key_threshold_notify(rx->dev, rx->key,
-                                                      rx->sta);
-               }
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
-{
-       struct sta_info *sta = rx->sta;
-       struct net_device *dev = rx->dev;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
-
-       if (!sta)
-               return TXRX_CONTINUE;
-
-       /* Update last_rx only for IBSS packets which are for the current
-        * BSSID to avoid keeping the current IBSS network alive in cases where
-        * other STAs are using different BSSID. */
-       if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
-               if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
-                       sta->last_rx = jiffies;
-       } else
-       if (!is_multicast_ether_addr(hdr->addr1) ||
-           rx->sdata->type == IEEE80211_IF_TYPE_STA) {
-               /* Update last_rx only for unicast frames in order to prevent
-                * the Probe Request frames (the only broadcast frames from a
-                * STA in infrastructure mode) from keeping a connection alive.
-                */
-               sta->last_rx = jiffies;
-       }
-
-       if (!rx->u.rx.ra_match)
-               return TXRX_CONTINUE;
-
-       sta->rx_fragments++;
-       sta->rx_bytes += rx->skb->len;
-       sta->last_rssi = (sta->last_rssi * 15 +
-                         rx->u.rx.status->ssi) / 16;
-       sta->last_signal = (sta->last_signal * 15 +
-                           rx->u.rx.status->signal) / 16;
-       sta->last_noise = (sta->last_noise * 15 +
-                          rx->u.rx.status->noise) / 16;
-
-       if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
-               /* Change STA power saving mode only in the end of a frame
-                * exchange sequence */
-               if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
-                       rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
-               else if (!(sta->flags & WLAN_STA_PS) &&
-                        (rx->fc & IEEE80211_FCTL_PM))
-                       ap_sta_ps_start(dev, sta);
-       }
-
-       /* Drop data::nullfunc frames silently, since they are used only to
-        * control station power saving mode. */
-       if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-           (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) {
-               I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
-               /* Update counter and free packet here to avoid counting this
-                * as a dropped packed. */
-               sta->rx_packets++;
-               dev_kfree_skb(rx->skb);
-               return TXRX_QUEUED;
-       }
-
-       return TXRX_CONTINUE;
-} /* ieee80211_rx_h_sta_process */
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
-{
-       if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
-           (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match)
-               return TXRX_CONTINUE;
-
-       /* Check for weak IVs, if hwaccel did not remove IV from the frame */
-       if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) ||
-           rx->key->force_sw_encrypt) {
-               u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key);
-               if (iv) {
-                       rx->sta->wep_weak_iv_count++;
-               }
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
-{
-       /* If the device handles decryption totally, skip this test */
-       if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
-               return TXRX_CONTINUE;
-
-       if ((rx->key && rx->key->alg != ALG_WEP) ||
-           !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
-           ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
-            ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-             (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
-               return TXRX_CONTINUE;
-
-       if (!rx->key) {
-               printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n",
-                      rx->dev->name);
-               return TXRX_DROP;
-       }
-
-       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) ||
-           rx->key->force_sw_encrypt) {
-               if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
-                       printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
-                              "failed\n", rx->dev->name);
-                       return TXRX_DROP;
-               }
-       } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
-               ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
-               /* remove ICV */
-               skb_trim(rx->skb, rx->skb->len - 4);
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
-{
-       if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
-           rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) {
-               /* Pass both encrypted and unencrypted EAPOL frames to user
-                * space for processing. */
-               if (!rx->local->apdev)
-                       return TXRX_DROP;
-               ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-                                 ieee80211_msg_normal);
-               return TXRX_QUEUED;
-       }
-
-       if (unlikely(rx->sdata->ieee802_1x &&
-                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-                    (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
-                    (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
-                    !ieee80211_is_eapol(rx->skb))) {
-#ifdef CONFIG_MAC80211_DEBUG
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) rx->skb->data;
-               printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
-                      " (unauthorized port)\n", rx->dev->name,
-                      MAC_ARG(hdr->addr2));
-#endif /* CONFIG_MAC80211_DEBUG */
-               return TXRX_DROP;
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
-{
-       /*  If the device handles decryption totally, skip this test */
-       if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
-               return TXRX_CONTINUE;
-
-       /* Drop unencrypted frames if key is set. */
-       if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
-                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-                    (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
-                    (rx->key || rx->sdata->drop_unencrypted) &&
-                    (rx->sdata->eapol == 0 ||
-                     !ieee80211_is_eapol(rx->skb)))) {
-               printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
-                      "encryption\n", rx->dev->name);
-               return TXRX_DROP;
-       }
-       return TXRX_CONTINUE;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       if (!rx->u.rx.ra_match)
-               return TXRX_DROP;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       if ((sdata->type == IEEE80211_IF_TYPE_STA ||
-            sdata->type == IEEE80211_IF_TYPE_IBSS) &&
-           !rx->local->user_space_mlme) {
-               ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
-       } else {
-               /* Management frames are sent to hostapd for processing */
-               if (!rx->local->apdev)
-                       return TXRX_DROP;
-               ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-                                 ieee80211_msg_normal);
-       }
-       return TXRX_QUEUED;
-}
-
-
-static ieee80211_txrx_result
-ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
-{
-       struct ieee80211_local *local = rx->local;
-       struct sk_buff *skb = rx->skb;
-
-       if (unlikely(local->sta_scanning != 0)) {
-               ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
-               return TXRX_QUEUED;
-       }
-
-       if (unlikely(rx->u.rx.in_scan)) {
-               /* scanning finished during invoking of handlers */
-               I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
-               return TXRX_DROP;
-       }
-
-       return TXRX_CONTINUE;
-}
-
-
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
-                                           struct ieee80211_hdr *hdr,
-                                           struct sta_info *sta,
-                                           struct ieee80211_txrx_data *rx)
-{
-       int keyidx, hdrlen;
-
-       hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
-       if (rx->skb->len >= hdrlen + 4)
-               keyidx = rx->skb->data[hdrlen + 3] >> 6;
-       else
-               keyidx = -1;
-
-       /* TODO: verify that this is not triggered by fragmented
-        * frames (hw does not verify MIC for them). */
-       printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
-              "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
-              dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx);
-
-       if (!sta) {
-               /* Some hardware versions seem to generate incorrect
-                * Michael MIC reports; ignore them to avoid triggering
-                * countermeasures. */
-               printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
-                      "error for unknown address " MAC_FMT "\n",
-                      dev->name, MAC_ARG(hdr->addr2));
-               goto ignore;
-       }
-
-       if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) {
-               printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
-                      "error for a frame with no ISWEP flag (src "
-                      MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
-               goto ignore;
-       }
-
-       if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
-           rx->sdata->type == IEEE80211_IF_TYPE_AP) {
-               keyidx = ieee80211_wep_get_keyidx(rx->skb);
-               /* AP with Pairwise keys support should never receive Michael
-                * MIC errors for non-zero keyidx because these are reserved
-                * for group keys and only the AP is sending real multicast
-                * frames in BSS. */
-               if (keyidx) {
-                       printk(KERN_DEBUG "%s: ignored Michael MIC error for "
-                              "a frame with non-zero keyidx (%d) (src " MAC_FMT
-                              ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2));
-                       goto ignore;
-               }
-       }
-
-       if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
-           ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-            (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) {
-               printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
-                      "error for a frame that cannot be encrypted "
-                      "(fc=0x%04x) (src " MAC_FMT ")\n",
-                      dev->name, rx->fc, MAC_ARG(hdr->addr2));
-               goto ignore;
-       }
-
-       do {
-               union iwreq_data wrqu;
-               char *buf = kmalloc(128, GFP_ATOMIC);
-               if (!buf)
-                       break;
-
-               /* TODO: needed parameters: count, key type, TSC */
-               sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-                       "keyid=%d %scast addr=" MAC_FMT ")",
-                       keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
-                       MAC_ARG(hdr->addr2));
-               memset(&wrqu, 0, sizeof(wrqu));
-               wrqu.data.length = strlen(buf);
-               wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
-               kfree(buf);
-       } while (0);
-
-       /* TODO: consider verifying the MIC error report with software
-        * implementation if we get too many spurious reports from the
-        * hardware. */
-       if (!rx->local->apdev)
-               goto ignore;
-       ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-                         ieee80211_msg_michael_mic_failure);
-       return;
-
- ignore:
-       dev_kfree_skb(rx->skb);
-       rx->skb = NULL;
-}
-
-static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
-                               struct ieee80211_local *local,
-                               ieee80211_rx_handler *handlers,
-                               struct ieee80211_txrx_data *rx,
-                               struct sta_info *sta)
-{
-       ieee80211_rx_handler *handler;
-       ieee80211_txrx_result res = TXRX_DROP;
-
-       for (handler = handlers; *handler != NULL; handler++) {
-               res = (*handler)(rx);
-               if (res != TXRX_CONTINUE) {
-                       if (res == TXRX_DROP) {
-                               I802_DEBUG_INC(local->rx_handlers_drop);
-                               if (sta)
-                                       sta->rx_dropped++;
-                       }
-                       if (res == TXRX_QUEUED)
-                               I802_DEBUG_INC(local->rx_handlers_queued);
-                       break;
-               }
-       }
-
-       if (res == TXRX_DROP) {
-               dev_kfree_skb(rx->skb);
-       }
-       return res;
-}
-
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-                                               ieee80211_rx_handler *handlers,
-                                               struct ieee80211_txrx_data *rx,
-                                               struct sta_info *sta)
-{
-       if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
-           TXRX_CONTINUE)
-               dev_kfree_skb(rx->skb);
-}
-
-/*
- * This is the receive path handler. It is called by a low level driver when an
- * 802.11 MPDU is received from the hardware.
- */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta;
-       struct ieee80211_hdr *hdr;
-       struct ieee80211_txrx_data rx;
-       u16 type;
-       int multicast;
-       int radiotap_len = 0;
-
-       if (status->flag & RX_FLAG_RADIOTAP) {
-               radiotap_len = ieee80211_get_radiotap_len(skb);
-               skb_pull(skb, radiotap_len);
-       }
-
-       hdr = (struct ieee80211_hdr *) skb->data;
-       memset(&rx, 0, sizeof(rx));
-       rx.skb = skb;
-       rx.local = local;
-
-       rx.u.rx.status = status;
-       rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0;
-       type = rx.fc & IEEE80211_FCTL_FTYPE;
-       if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
-               local->dot11ReceivedFragmentCount++;
-       multicast = is_multicast_ether_addr(hdr->addr1);
-
-       if (skb->len >= 16)
-               sta = rx.sta = sta_info_get(local, hdr->addr2);
-       else
-               sta = rx.sta = NULL;
-
-       if (sta) {
-               rx.dev = sta->dev;
-               rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
-       }
-
-       if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
-               goto end;
-       }
-
-       if (unlikely(local->sta_scanning))
-               rx.u.rx.in_scan = 1;
-
-       if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
-                                          sta) != TXRX_CONTINUE)
-               goto end;
-       skb = rx.skb;
-
-       skb_push(skb, radiotap_len);
-       if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
-           !local->iff_promiscs && !multicast) {
-               rx.u.rx.ra_match = 1;
-               ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
-                                            sta);
-       } else {
-               struct ieee80211_sub_if_data *prev = NULL;
-               struct sk_buff *skb_new;
-               u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
-
-               read_lock(&local->sub_if_lock);
-               list_for_each_entry(sdata, &local->sub_if_list, list) {
-                       rx.u.rx.ra_match = 1;
-                       switch (sdata->type) {
-                       case IEEE80211_IF_TYPE_STA:
-                               if (!bssid)
-                                       continue;
-                               if (!ieee80211_bssid_match(bssid,
-                                                       sdata->u.sta.bssid)) {
-                                       if (!rx.u.rx.in_scan)
-                                               continue;
-                                       rx.u.rx.ra_match = 0;
-                               } else if (!multicast &&
-                                          compare_ether_addr(sdata->dev->dev_addr,
-                                                             hdr->addr1) != 0) {
-                                       if (!sdata->promisc)
-                                               continue;
-                                       rx.u.rx.ra_match = 0;
-                               }
-                               break;
-                       case IEEE80211_IF_TYPE_IBSS:
-                               if (!bssid)
-                                       continue;
-                               if (!ieee80211_bssid_match(bssid,
-                                                       sdata->u.sta.bssid)) {
-                                       if (!rx.u.rx.in_scan)
-                                               continue;
-                                       rx.u.rx.ra_match = 0;
-                               } else if (!multicast &&
-                                          compare_ether_addr(sdata->dev->dev_addr,
-                                                             hdr->addr1) != 0) {
-                                       if (!sdata->promisc)
-                                               continue;
-                                       rx.u.rx.ra_match = 0;
-                               } else if (!sta)
-                                       sta = rx.sta =
-                                               ieee80211_ibss_add_sta(sdata->dev,
-                                                                      skb, bssid,
-                                                                      hdr->addr2);
-                               break;
-                       case IEEE80211_IF_TYPE_AP:
-                               if (!bssid) {
-                                       if (compare_ether_addr(sdata->dev->dev_addr,
-                                                              hdr->addr1) != 0)
-                                               continue;
-                               } else if (!ieee80211_bssid_match(bssid,
-                                                       sdata->dev->dev_addr)) {
-                                       if (!rx.u.rx.in_scan)
-                                               continue;
-                                       rx.u.rx.ra_match = 0;
-                               }
-                               if (sdata->dev == local->mdev &&
-                                   !rx.u.rx.in_scan)
-                                       /* do not receive anything via
-                                        * master device when not scanning */
-                                       continue;
-                               break;
-                       case IEEE80211_IF_TYPE_WDS:
-                               if (bssid ||
-                                   (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-                                       continue;
-                               if (compare_ether_addr(sdata->u.wds.remote_addr,
-                                                      hdr->addr2) != 0)
-                                       continue;
-                               break;
-                       }
-
-                       if (prev) {
-                               skb_new = skb_copy(skb, GFP_ATOMIC);
-                               if (!skb_new) {
-                                       if (net_ratelimit())
-                                               printk(KERN_DEBUG "%s: failed to copy "
-                                                      "multicast frame for %s",
-                                                      local->mdev->name, prev->dev->name);
-                                       continue;
-                               }
-                               rx.skb = skb_new;
-                               rx.dev = prev->dev;
-                               rx.sdata = prev;
-                               ieee80211_invoke_rx_handlers(local,
-                                                            local->rx_handlers,
-                                                            &rx, sta);
-                       }
-                       prev = sdata;
-               }
-               if (prev) {
-                       rx.skb = skb;
-                       rx.dev = prev->dev;
-                       rx.sdata = prev;
-                       ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-                                                    &rx, sta);
-               } else
-                       dev_kfree_skb(skb);
-               read_unlock(&local->sub_if_lock);
+               tasklet_disable(&local->tx_pending_tasklet);
+               tasklet_disable(&local->tasklet);
        }
 
-  end:
-       if (sta)
-               sta_info_put(sta);
+       return 0;
 }
-EXPORT_SYMBOL(__ieee80211_rx);
 
-static ieee80211_txrx_result
-ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+static void ieee80211_set_multicast_list(struct net_device *dev)
 {
-       struct ieee80211_local *local = tx->local;
-       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
-       struct sk_buff *skb = tx->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u32 load = 0, hdrtime;
-
-       /* TODO: this could be part of tx_status handling, so that the number
-        * of retries would be known; TX rate should in that case be stored
-        * somewhere with the packet */
-
-       /* Estimate total channel use caused by this frame */
-
-       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
-        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
-       if (mode->mode == MODE_IEEE80211A ||
-           mode->mode == MODE_ATHEROS_TURBO ||
-           mode->mode == MODE_ATHEROS_TURBOG ||
-           (mode->mode == MODE_IEEE80211G &&
-            tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
-               hdrtime = CHAN_UTIL_HDR_SHORT;
-       else
-               hdrtime = CHAN_UTIL_HDR_LONG;
-
-       load = hdrtime;
-       if (!is_multicast_ether_addr(hdr->addr1))
-               load += hdrtime;
-
-       if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
-               load += 2 * hdrtime;
-       else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
-               load += hdrtime;
-
-       load += skb->len * tx->u.tx.rate->rate_inv;
-
-       if (tx->u.tx.extra_frag) {
-               int i;
-               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-                       load += 2 * hdrtime;
-                       load += tx->u.tx.extra_frag[i]->len *
-                               tx->u.tx.rate->rate;
-               }
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int allmulti, promisc, sdata_allmulti, sdata_promisc;
+
+       allmulti = !!(dev->flags & IFF_ALLMULTI);
+       promisc = !!(dev->flags & IFF_PROMISC);
+       sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+       sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+
+       if (allmulti != sdata_allmulti) {
+               if (dev->flags & IFF_ALLMULTI)
+                       atomic_inc(&local->iff_allmultis);
+               else
+                       atomic_dec(&local->iff_allmultis);
+               sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
+       }
+
+       if (promisc != sdata_promisc) {
+               if (dev->flags & IFF_PROMISC)
+                       atomic_inc(&local->iff_promiscs);
+               else
+                       atomic_dec(&local->iff_promiscs);
+               sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
 
-       /* Divide channel_use by 8 to avoid wrapping around the counter */
-       load >>= CHAN_UTIL_SHIFT;
-       local->channel_use_raw += load;
-       if (tx->sta)
-               tx->sta->channel_use_raw += load;
-       tx->sdata->channel_use_raw += load;
+       dev_mc_sync(local->mdev, dev);
+}
 
-       return TXRX_CONTINUE;
+/* Must not be called for mdev */
+void ieee80211_if_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+       dev->hard_start_xmit = ieee80211_subif_start_xmit;
+       dev->wireless_handlers = &ieee80211_iw_handler_def;
+       dev->set_multicast_list = ieee80211_set_multicast_list;
+       dev->change_mtu = ieee80211_change_mtu;
+       dev->open = ieee80211_open;
+       dev->stop = ieee80211_stop;
+       dev->destructor = ieee80211_if_free;
 }
 
+/* WDS specialties */
 
-static ieee80211_txrx_result
-ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
 {
-       struct ieee80211_local *local = rx->local;
-       struct sk_buff *skb = rx->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u32 load = 0, hdrtime;
-       struct ieee80211_rate *rate;
-       struct ieee80211_hw_mode *mode = local->hw.conf.mode;
-       int i;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct sta_info *sta;
 
-       /* Estimate total channel use caused by this frame */
+       if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
+               return 0;
 
-       if (unlikely(mode->num_rates < 0))
-               return TXRX_CONTINUE;
+       /* Create STA entry for the new peer */
+       sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
+       if (!sta)
+               return -ENOMEM;
+       sta_info_put(sta);
 
-       rate = &mode->rates[0];
-       for (i = 0; i < mode->num_rates; i++) {
-               if (mode->rates[i].val == rx->u.rx.status->rate) {
-                       rate = &mode->rates[i];
-                       break;
-               }
+       /* Remove STA entry for the old peer */
+       sta = sta_info_get(local, sdata->u.wds.remote_addr);
+       if (sta) {
+               sta_info_free(sta);
+               sta_info_put(sta);
+       } else {
+               printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
+                      "peer " MAC_FMT "\n",
+                      dev->name, MAC_ARG(sdata->u.wds.remote_addr));
        }
 
-       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
-        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+       /* Update WDS link data */
+       memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
 
-       if (mode->mode == MODE_IEEE80211A ||
-           mode->mode == MODE_ATHEROS_TURBO ||
-           mode->mode == MODE_ATHEROS_TURBOG ||
-           (mode->mode == MODE_IEEE80211G &&
-            rate->flags & IEEE80211_RATE_ERP))
-               hdrtime = CHAN_UTIL_HDR_SHORT;
-       else
-               hdrtime = CHAN_UTIL_HDR_LONG;
+       return 0;
+}
 
-       load = hdrtime;
-       if (!is_multicast_ether_addr(hdr->addr1))
-               load += hdrtime;
+/* everything else */
 
-       load += skb->len * rate->rate_inv;
+static int __ieee80211_if_config(struct net_device *dev,
+                                struct sk_buff *beacon,
+                                struct ieee80211_tx_control *control)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_if_conf conf;
 
-       /* Divide channel_use by 8 to avoid wrapping around the counter */
-       load >>= CHAN_UTIL_SHIFT;
-       local->channel_use_raw += load;
-       if (rx->sta)
-               rx->sta->channel_use_raw += load;
-       rx->u.rx.load = load;
+       if (!local->ops->config_interface || !netif_running(dev))
+               return 0;
 
-       return TXRX_CONTINUE;
+       memset(&conf, 0, sizeof(conf));
+       conf.type = sdata->type;
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               conf.bssid = sdata->u.sta.bssid;
+               conf.ssid = sdata->u.sta.ssid;
+               conf.ssid_len = sdata->u.sta.ssid_len;
+       } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+               conf.ssid = sdata->u.ap.ssid;
+               conf.ssid_len = sdata->u.ap.ssid_len;
+               conf.beacon = beacon;
+               conf.beacon_control = control;
+       }
+       return local->ops->config_interface(local_to_hw(local),
+                                          dev->ifindex, &conf);
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+int ieee80211_if_config(struct net_device *dev)
 {
-       rx->sdata->channel_use_raw += rx->u.rx.load;
-       return TXRX_CONTINUE;
+       return __ieee80211_if_config(dev, NULL, NULL);
 }
 
-static void ieee80211_stat_refresh(unsigned long data)
+int ieee80211_if_config_beacon(struct net_device *dev)
 {
-       struct ieee80211_local *local = (struct ieee80211_local *) data;
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_tx_control control;
+       struct sk_buff *skb;
 
-       if (!local->stat_time)
-               return;
+       if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+               return 0;
+       skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+       if (!skb)
+               return -ENOMEM;
+       return __ieee80211_if_config(dev, skb, &control);
+}
+
+int ieee80211_hw_config(struct ieee80211_local *local)
+{
+       struct ieee80211_hw_mode *mode;
+       struct ieee80211_channel *chan;
+       int ret = 0;
 
-       /* go through all stations */
-       spin_lock_bh(&local->sta_lock);
-       list_for_each_entry(sta, &local->sta_list, list) {
-               sta->channel_use = (sta->channel_use_raw / local->stat_time) /
-                       CHAN_UTIL_PER_10MS;
-               sta->channel_use_raw = 0;
+       if (local->sta_scanning) {
+               chan = local->scan_channel;
+               mode = local->scan_hw_mode;
+       } else {
+               chan = local->oper_channel;
+               mode = local->oper_hw_mode;
        }
-       spin_unlock_bh(&local->sta_lock);
-
-       /* go through all subinterfaces */
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
-               sdata->channel_use = (sdata->channel_use_raw /
-                                     local->stat_time) / CHAN_UTIL_PER_10MS;
-               sdata->channel_use_raw = 0;
+
+       local->hw.conf.channel = chan->chan;
+       local->hw.conf.channel_val = chan->val;
+       if (!local->hw.conf.power_level) {
+               local->hw.conf.power_level = chan->power_level;
+       } else {
+               local->hw.conf.power_level = min(chan->power_level,
+                                                local->hw.conf.power_level);
        }
-       read_unlock(&local->sub_if_lock);
+       local->hw.conf.freq = chan->freq;
+       local->hw.conf.phymode = mode->mode;
+       local->hw.conf.antenna_max = chan->antenna_max;
+       local->hw.conf.chan = chan;
+       local->hw.conf.mode = mode;
 
-       /* hardware interface */
-       local->channel_use = (local->channel_use_raw /
-                             local->stat_time) / CHAN_UTIL_PER_10MS;
-       local->channel_use_raw = 0;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
+              "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
+              local->hw.conf.phymode);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-       local->stat_timer.expires = jiffies + HZ * local->stat_time / 100;
-       add_timer(&local->stat_timer);
-}
+       if (local->open_count)
+               ret = local->ops->config(local_to_hw(local), &local->hw.conf);
 
+       return ret;
+}
 
-/* This is a version of the rx handler that can be called from hard irq
- * context. Post the skb on the queue and schedule the tasklet */
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
-                         struct ieee80211_rx_status *status)
+void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (local->ops->erp_ie_changed)
+               local->ops->erp_ie_changed(local_to_hw(local), changes,
+                       !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION),
+                       !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE));
+}
 
-       BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
+void ieee80211_reset_erp_info(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       skb->dev = local->mdev;
-       /* copy status into skb->cb for use by tasklet */
-       memcpy(skb->cb, status, sizeof(*status));
-       skb->pkt_type = IEEE80211_RX_MSG;
-       skb_queue_tail(&local->skb_queue, skb);
-       tasklet_schedule(&local->tasklet);
+       sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION |
+                       IEEE80211_SDATA_SHORT_PREAMBLE);
+       ieee80211_erp_info_change_notify(dev,
+                                        IEEE80211_ERP_CHANGE_PROTECTION |
+                                        IEEE80211_ERP_CHANGE_PREAMBLE);
 }
-EXPORT_SYMBOL(ieee80211_rx_irqsafe);
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
                                 struct sk_buff *skb,
@@ -4347,14 +613,13 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        break;
                default: /* should never get here! */
                        printk(KERN_ERR "%s: Unknown message type (%d)\n",
-                              local->mdev->name, skb->pkt_type);
+                              wiphy_name(local->hw.wiphy), skb->pkt_type);
                        dev_kfree_skb(skb);
                        break;
                }
        }
 }
 
-
 /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
  * make a prepared TX frame (one that has been given to hw) to look like brand
  * new IEEE 802.11 frame that is ready to go through TX processing again.
@@ -4369,10 +634,13 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
 
        pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
        pkt_data->ifindex = control->ifindex;
-       pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT);
-       pkt_data->req_tx_status = !!(control->flags & IEEE80211_TXCTL_REQ_TX_STATUS);
-       pkt_data->do_not_encrypt = !!(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT);
-       pkt_data->requeue = !!(control->flags & IEEE80211_TXCTL_REQUEUE);
+       pkt_data->flags = 0;
+       if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
+               pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
+       if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
+               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+       if (control->flags & IEEE80211_TXCTL_REQUEUE)
+               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
        pkt_data->queue = control->queue;
 
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -4380,7 +648,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
        if (!key)
                goto no_key;
 
-       switch (key->alg) {
+       switch (key->conf.alg) {
        case ALG_WEP:
                iv_len = WEP_IV_LEN;
                mic_len = WEP_ICV_LEN;
@@ -4397,7 +665,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                goto no_key;
        }
 
-       if (skb->len >= mic_len && key->force_sw_encrypt)
+       if (skb->len >= mic_len &&
+           !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
                skb_trim(skb, skb->len - mic_len);
        if (skb->len >= iv_len && skb->len > hdrlen) {
                memmove(skb->data + iv_len, skb->data, hdrlen);
@@ -4417,7 +686,6 @@ no_key:
        }
 }
 
-
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                         struct ieee80211_tx_status *status)
 {
@@ -4425,12 +693,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_local *local = hw_to_local(hw);
        u16 frag, type;
-       u32 msg_type;
+       struct ieee80211_tx_status_rtap_hdr *rthdr;
+       struct ieee80211_sub_if_data *sdata;
+       int monitors;
 
        if (!status) {
                printk(KERN_ERR
                       "%s: ieee80211_tx_status called with NULL status\n",
-                      local->mdev->name);
+                      wiphy_name(local->hw.wiphy));
                dev_kfree_skb(skb);
                return;
        }
@@ -4487,7 +757,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                                        printk(KERN_DEBUG "%s: dropped TX "
                                               "filtered frame queue_len=%d "
                                               "PS=%d @%lu\n",
-                                              local->mdev->name,
+                                              wiphy_name(local->hw.wiphy),
                                               skb_queue_len(
                                                       &sta->tx_filtered),
                                               !!(sta->flags & WLAN_STA_PS),
@@ -4537,189 +807,81 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                        local->dot11FailedCount++;
        }
 
-       if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)
-           || unlikely(!local->apdev)) {
+       /* this was a transmitted frame, but now we want to reuse it */
+       skb_orphan(skb);
+
+       if (!local->monitors) {
                dev_kfree_skb(skb);
                return;
        }
 
-       msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
-               ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+       /* send frame to monitor interfaces now */
 
-       /* skb was the original skb used for TX. Clone it and give the clone
-        * to netif_rx(). Free original skb. */
-       skb2 = skb_copy(skb, GFP_ATOMIC);
-       if (!skb2) {
+       if (skb_headroom(skb) < sizeof(*rthdr)) {
+               printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
                dev_kfree_skb(skb);
                return;
        }
-       dev_kfree_skb(skb);
-       skb = skb2;
-
-       /* Send frame to hostapd */
-       ieee80211_rx_mgmt(local, skb, NULL, msg_type);
-}
-EXPORT_SYMBOL(ieee80211_tx_status);
-
-/* TODO: implement register/unregister functions for adding TX/RX handlers
- * into ordered list */
-
-/* rx_pre handlers don't have dev and sdata fields available in
- * ieee80211_txrx_data */
-static ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
-{
-       ieee80211_rx_h_parse_qos,
-       ieee80211_rx_h_load_stats,
-       NULL
-};
-
-static ieee80211_rx_handler ieee80211_rx_handlers[] =
-{
-       ieee80211_rx_h_if_stats,
-       ieee80211_rx_h_monitor,
-       ieee80211_rx_h_passive_scan,
-       ieee80211_rx_h_check,
-       ieee80211_rx_h_sta_process,
-       ieee80211_rx_h_ccmp_decrypt,
-       ieee80211_rx_h_tkip_decrypt,
-       ieee80211_rx_h_wep_weak_iv_detection,
-       ieee80211_rx_h_wep_decrypt,
-       ieee80211_rx_h_defragment,
-       ieee80211_rx_h_ps_poll,
-       ieee80211_rx_h_michael_mic_verify,
-       /* this must be after decryption - so header is counted in MPDU mic
-        * must be before pae and data, so QOS_DATA format frames
-        * are not passed to user space by these functions
-        */
-       ieee80211_rx_h_remove_qos_control,
-       ieee80211_rx_h_802_1x_pae,
-       ieee80211_rx_h_drop_unencrypted,
-       ieee80211_rx_h_data_agg,
-       ieee80211_rx_h_data,
-       ieee80211_rx_h_mgmt,
-       NULL
-};
-
-static ieee80211_tx_handler ieee80211_tx_handlers[] =
-{
-       ieee80211_tx_h_check_assoc,
-       ieee80211_tx_h_sequence,
-       ieee80211_tx_h_ps_buf,
-       ieee80211_tx_h_select_key,
-       ieee80211_tx_h_michael_mic_add,
-       ieee80211_tx_h_fragment,
-       ieee80211_tx_h_tkip_encrypt,
-       ieee80211_tx_h_ccmp_encrypt,
-       ieee80211_tx_h_wep_encrypt,
-       ieee80211_tx_h_rate_ctrl,
-       ieee80211_tx_h_misc,
-       ieee80211_tx_h_load_stats,
-       NULL
-};
-
-
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct sta_info *sta;
-
-       if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
-               return 0;
-
-       /* Create STA entry for the new peer */
-       sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
-       if (!sta)
-               return -ENOMEM;
-       sta_info_put(sta);
 
-       /* Remove STA entry for the old peer */
-       sta = sta_info_get(local, sdata->u.wds.remote_addr);
-       if (sta) {
-               sta_info_put(sta);
-               sta_info_free(sta, 0);
-       } else {
-               printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
-                      "peer " MAC_FMT "\n",
-                      dev->name, MAC_ARG(sdata->u.wds.remote_addr));
-       }
+       rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+                               skb_push(skb, sizeof(*rthdr));
 
-       /* Update WDS link data */
-       memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
+       memset(rthdr, 0, sizeof(*rthdr));
+       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+       rthdr->hdr.it_present =
+               cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
 
-       return 0;
-}
+       if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+           !is_multicast_ether_addr(hdr->addr1))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
 
-/* Must not be called for mdev and apdev */
-void ieee80211_if_setup(struct net_device *dev)
-{
-       ether_setup(dev);
-       dev->hard_start_xmit = ieee80211_subif_start_xmit;
-       dev->wireless_handlers = &ieee80211_iw_handler_def;
-       dev->do_ioctl = ieee80211_ioctl;
-       dev->set_multicast_list = ieee80211_set_multicast_list;
-       dev->change_mtu = ieee80211_change_mtu;
-       dev->get_stats = ieee80211_get_stats;
-       dev->open = ieee80211_open;
-       dev->stop = ieee80211_stop;
-       dev->uninit = ieee80211_if_reinit;
-       dev->destructor = ieee80211_if_free;
-}
+       if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
+           (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+       else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
 
-void ieee80211_if_mgmt_setup(struct net_device *dev)
-{
-       ether_setup(dev);
-       dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
-       dev->change_mtu = ieee80211_change_mtu_apdev;
-       dev->get_stats = ieee80211_get_stats;
-       dev->open = ieee80211_mgmt_open;
-       dev->stop = ieee80211_mgmt_stop;
-       dev->type = ARPHRD_IEEE80211_PRISM;
-       dev->hard_header_parse = header_parse_80211;
-       dev->uninit = ieee80211_if_reinit;
-       dev->destructor = ieee80211_if_free;
-}
+       rthdr->data_retries = status->retry_count;
 
-int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
-                                const char *name)
-{
-       struct rate_control_ref *ref, *old;
-
-       ASSERT_RTNL();
-       if (local->open_count || netif_running(local->mdev) ||
-           (local->apdev && netif_running(local->apdev)))
-               return -EBUSY;
-
-       ref = rate_control_alloc(name, local);
-       if (!ref) {
-               printk(KERN_WARNING "%s: Failed to select rate control "
-                      "algorithm\n", local->mdev->name);
-               return -ENOENT;
-       }
+       rcu_read_lock();
+       monitors = local->monitors;
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               /*
+                * Using the monitors counter is possibly racy, but
+                * if the value is wrong we simply either clone the skb
+                * once too much or forget sending it to one monitor iface
+                * The latter case isn't nice but fixing the race is much
+                * more complicated.
+                */
+               if (!monitors || !skb)
+                       goto out;
 
-       old = local->rate_ctrl;
-       local->rate_ctrl = ref;
-       if (old) {
-               rate_control_put(old);
-               sta_info_flush(local, NULL);
+               if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+                       if (!netif_running(sdata->dev))
+                               continue;
+                       monitors--;
+                       if (monitors)
+                               skb2 = skb_clone(skb, GFP_ATOMIC);
+                       else
+                               skb2 = NULL;
+                       skb->dev = sdata->dev;
+                       /* XXX: is this sufficient for BPF? */
+                       skb_set_mac_header(skb, 0);
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       skb->pkt_type = PACKET_OTHERHOST;
+                       skb->protocol = htons(ETH_P_802_2);
+                       memset(skb->cb, 0, sizeof(skb->cb));
+                       netif_rx(skb);
+                       skb = skb2;
+               }
        }
-
-       printk(KERN_DEBUG "%s: Selected rate control "
-              "algorithm '%s'\n", local->mdev->name,
-              ref->ops->name);
-
-
-       return 0;
-}
-
-static void rate_control_deinitialize(struct ieee80211_local *local)
-{
-       struct rate_control_ref *ref;
-
-       ref = local->rate_ctrl;
-       local->rate_ctrl = NULL;
-       rate_control_put(ref);
+ out:
+       rcu_read_unlock();
+       if (skb)
+               dev_kfree_skb(skb);
 }
+EXPORT_SYMBOL(ieee80211_tx_status);
 
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
@@ -4763,6 +925,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                         ((sizeof(struct ieee80211_local) +
                           NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
 
+       BUG_ON(!ops->tx);
+       BUG_ON(!ops->start);
+       BUG_ON(!ops->stop);
+       BUG_ON(!ops->config);
+       BUG_ON(!ops->add_interface);
+       BUG_ON(!ops->remove_interface);
+       BUG_ON(!ops->configure_filter);
        local->ops = ops;
 
        /* for now, mdev needs sub_if_data :/ */
@@ -4791,20 +960,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->short_retry_limit = 7;
        local->long_retry_limit = 4;
        local->hw.conf.radio_enabled = 1;
-       local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
-       local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
 
-       local->enabled_modes = (unsigned int) -1;
+       local->enabled_modes = ~0;
 
        INIT_LIST_HEAD(&local->modes_list);
 
-       rwlock_init(&local->sub_if_lock);
-       INIT_LIST_HEAD(&local->sub_if_list);
+       INIT_LIST_HEAD(&local->interfaces);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
-       init_timer(&local->stat_timer);
-       local->stat_timer.function = ieee80211_stat_refresh;
-       local->stat_timer.data = (unsigned long) local;
        ieee80211_rx_bss_list_init(mdev);
 
        sta_info_init(local);
@@ -4814,6 +977,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        mdev->stop = ieee80211_master_stop;
        mdev->type = ARPHRD_IEEE80211;
        mdev->hard_header_parse = header_parse_80211;
+       mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
        sdata->type = IEEE80211_IF_TYPE_AP;
        sdata->dev = mdev;
@@ -4821,7 +985,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        sdata->u.ap.force_unicast_rateidx = -1;
        sdata->u.ap.max_ratectrl_rateidx = -1;
        ieee80211_if_sdata_init(sdata);
-       list_add_tail(&sdata->list, &local->sub_if_list);
+       /* no RCU needed since we're still during init phase */
+       list_add_tail(&sdata->list, &local->interfaces);
 
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
                     (unsigned long)local);
@@ -4856,6 +1021,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_workqueue;
        }
 
+       /*
+        * The hardware needs headroom for sending the frame,
+        * and we need some headroom for passing the frame to monitor
+        * interfaces, but never both at the same time.
+        */
+       local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
+                                  sizeof(struct ieee80211_tx_status_rtap_hdr));
+
        debugfs_hw_add(local);
 
        local->hw.conf.beacon_int = 1000;
@@ -4886,11 +1059,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_dev;
 
        ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
+       ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
 
        result = ieee80211_init_rate_ctrl_alg(local, NULL);
        if (result < 0) {
                printk(KERN_DEBUG "%s: Failed to initialize rate control "
-                      "algorithm\n", local->mdev->name);
+                      "algorithm\n", wiphy_name(local->hw.wiphy));
                goto fail_rate;
        }
 
@@ -4898,7 +1072,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        if (result < 0) {
                printk(KERN_DEBUG "%s: Failed to initialize wep\n",
-                      local->mdev->name);
+                      wiphy_name(local->hw.wiphy));
                goto fail_wep;
        }
 
@@ -4909,7 +1083,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                                  IEEE80211_IF_TYPE_STA);
        if (result)
                printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
-                      local->mdev->name);
+                      wiphy_name(local->hw.wiphy));
 
        local->reg_state = IEEE80211_DEV_REGISTERED;
        rtnl_unlock();
@@ -4972,7 +1146,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata, *tmp;
-       struct list_head tmp_list;
        int i;
 
        tasklet_kill(&local->tx_pending_tasklet);
@@ -4983,20 +1156,30 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
 
        local->reg_state = IEEE80211_DEV_UNREGISTERED;
-       if (local->apdev)
-               ieee80211_if_del_mgmt(local);
 
-       write_lock_bh(&local->sub_if_lock);
-       list_replace_init(&local->sub_if_list, &tmp_list);
-       write_unlock_bh(&local->sub_if_lock);
+       /*
+        * At this point, interface list manipulations are fine
+        * because the driver cannot be handing us frames any
+        * more and the tasklet is killed.
+        */
 
-       list_for_each_entry_safe(sdata, tmp, &tmp_list, list)
+       /*
+        * First, we remove all non-master interfaces. Do this because they
+        * may have bss pointer dependency on the master, and when we free
+        * the master these would be freed as well, breaking our list
+        * iteration completely.
+        */
+       list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
+               if (sdata->dev == local->mdev)
+                       continue;
+               list_del(&sdata->list);
                __ieee80211_if_del(local, sdata);
+       }
 
-       rtnl_unlock();
+       /* then, finally, remove the master interface */
+       __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
 
-       if (local->stat_time)
-               del_timer_sync(&local->stat_timer);
+       rtnl_unlock();
 
        ieee80211_rx_bss_list_deinit(local->mdev);
        ieee80211_clear_tx_pending(local);
@@ -5012,7 +1195,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        if (skb_queue_len(&local->skb_queue)
                        || skb_queue_len(&local->skb_queue_unreliable))
                printk(KERN_WARNING "%s: skb_queue not empty\n",
-                      local->mdev->name);
+                      wiphy_name(local->hw.wiphy));
        skb_queue_purge(&local->skb_queue);
        skb_queue_purge(&local->skb_queue_unreliable);
 
@@ -5032,72 +1215,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
 
-void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
-                              &local->state[queue])) {
-               if (test_bit(IEEE80211_LINK_STATE_PENDING,
-                            &local->state[queue]))
-                       tasklet_schedule(&local->tx_pending_tasklet);
-               else
-                       if (!ieee80211_qdisc_installed(local->mdev)) {
-                               if (queue == 0)
-                                       netif_wake_queue(local->mdev);
-                       } else
-                               __netif_schedule(local->mdev);
-       }
-}
-EXPORT_SYMBOL(ieee80211_wake_queue);
-
-void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
-               netif_stop_queue(local->mdev);
-       set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-EXPORT_SYMBOL(ieee80211_stop_queue);
-
-void ieee80211_start_queues(struct ieee80211_hw *hw)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       int i;
-
-       for (i = 0; i < local->hw.queues; i++)
-               clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
-       if (!ieee80211_qdisc_installed(local->mdev))
-               netif_start_queue(local->mdev);
-}
-EXPORT_SYMBOL(ieee80211_start_queues);
-
-void ieee80211_stop_queues(struct ieee80211_hw *hw)
-{
-       int i;
-
-       for (i = 0; i < hw->queues; i++)
-               ieee80211_stop_queue(hw, i);
-}
-EXPORT_SYMBOL(ieee80211_stop_queues);
-
-void ieee80211_wake_queues(struct ieee80211_hw *hw)
-{
-       int i;
-
-       for (i = 0; i < hw->queues; i++)
-               ieee80211_wake_queue(hw, i);
-}
-EXPORT_SYMBOL(ieee80211_wake_queues);
-
-struct net_device_stats *ieee80211_dev_stats(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata;
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       return &sdata->stats;
-}
-
 static int __init ieee80211_init(void)
 {
        struct sk_buff *skb;
@@ -5118,7 +1235,6 @@ static int __init ieee80211_init(void)
        return 0;
 }
 
-
 static void __exit ieee80211_exit(void)
 {
        ieee80211_wme_unregister();
@@ -5126,7 +1242,7 @@ static void __exit ieee80211_exit(void)
 }
 
 
-module_init(ieee80211_init);
+subsys_initcall(ieee80211_init);
 module_exit(ieee80211_exit);
 
 MODULE_DESCRIPTION("IEEE 802.11 subsystem");
diff --git a/package/mac80211/src/mac80211/ieee80211_cfg.c b/package/mac80211/src/mac80211/ieee80211_cfg.c
deleted file mode 100644 (file)
index 8f85bc2..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * mac80211 configuration hooks for cfg80211
- *
- * Copyright 2006      Johannes Berg <johannes@sipsolutions.net>
- *
- * This file is GPLv2 as found in COPYING.
- */
-
-#include <linux/nl80211.h>
-#include <linux/rtnetlink.h>
-#include <net/cfg80211.h>
-#include "ieee80211_i.h"
-#include "ieee80211_cfg.h"
-
-static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-                              enum nl80211_iftype type)
-{
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       int itype;
-
-       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-               return -ENODEV;
-
-       switch (type) {
-       case NL80211_IFTYPE_UNSPECIFIED:
-               itype = IEEE80211_IF_TYPE_STA;
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               itype = IEEE80211_IF_TYPE_IBSS;
-               break;
-       case NL80211_IFTYPE_STATION:
-               itype = IEEE80211_IF_TYPE_STA;
-               break;
-       case NL80211_IFTYPE_AP:
-               itype = IEEE80211_IF_TYPE_AP;
-               break;
-       case NL80211_IFTYPE_WDS:
-               itype = IEEE80211_IF_TYPE_WDS;
-               break;
-       case NL80211_IFTYPE_MONITOR:
-               itype = IEEE80211_IF_TYPE_MNTR;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return ieee80211_if_add(local->mdev, name, NULL, itype);
-}
-
-static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
-{
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct net_device *dev;
-       char *name;
-
-       if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-               return -ENODEV;
-
-       dev = dev_get_by_index(ifindex);
-       if (!dev)
-               return 0;
-
-       name = dev->name;
-       dev_put(dev);
-
-       return ieee80211_if_remove(local->mdev, name, -1);
-}
-
-struct cfg80211_ops mac80211_config_ops = {
-       .add_virtual_intf = ieee80211_add_iface,
-       .del_virtual_intf = ieee80211_del_iface,
-};
diff --git a/package/mac80211/src/mac80211/ieee80211_cfg.h b/package/mac80211/src/mac80211/ieee80211_cfg.h
deleted file mode 100644 (file)
index 85ed2c9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * mac80211 configuration hooks for cfg80211
- */
-#ifndef __IEEE80211_CFG_H
-#define __IEEE80211_CFG_H
-
-extern struct cfg80211_ops mac80211_config_ops;
-
-#endif /* __IEEE80211_CFG_H */
index b9a73e7f5f7599ef99a1f159916e45c0ab8dc303..c15295d43d87faa136584728a84143505a164b49 100644 (file)
@@ -47,19 +47,14 @@ enum ieee80211_msg_type {
        ieee80211_msg_normal = 0,
        ieee80211_msg_tx_callback_ack = 1,
        ieee80211_msg_tx_callback_fail = 2,
-       ieee80211_msg_passive_scan = 3,
-       ieee80211_msg_wep_frame_unknown_key = 4,
+       /* hole at 3, was ieee80211_msg_passive_scan but unused */
+       /* hole at 4, was ieee80211_msg_wep_frame_unknown_key but now unused */
        ieee80211_msg_michael_mic_failure = 5,
        /* hole at 6, was monitor but never sent to userspace */
        ieee80211_msg_sta_not_assoc = 7,
-       ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
-       ieee80211_msg_key_threshold_notification = 9,
-       ieee80211_msg_radar = 11,
-};
-
-struct ieee80211_msg_set_aid_for_sta {
-       char    sta_address[ETH_ALEN];
-       u16     aid;
+       /* 8 was ieee80211_msg_set_aid_for_sta */
+       /* 9 was ieee80211_msg_key_threshold_notification */
+       /* 11 was ieee80211_msg_radar */
 };
 
 struct ieee80211_msg_key_notification {
@@ -78,8 +73,6 @@ enum ieee80211_phytype {
        ieee80211_phytype_ofdm_dot11_g   = 6,
        ieee80211_phytype_pbcc_dot11_g   = 7,
        ieee80211_phytype_ofdm_dot11_a   = 8,
-       ieee80211_phytype_dsss_dot11_turbog = 255,
-       ieee80211_phytype_dsss_dot11_turbo = 256,
 };
 
 enum ieee80211_ssi_type {
index 880a73075e958cb959c1fe5c0115c639904d435f..d34a9deca67ad25bc36c44c3422dae6128548e42 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/etherdevice.h>
 #include <net/wireless.h>
 #include "ieee80211_key.h"
 #include "sta_info.h"
@@ -59,10 +60,6 @@ struct ieee80211_local;
  * increased memory use (about 2 kB of RAM per entry). */
 #define IEEE80211_FRAGMENT_MAX 4
 
-/* Minimum and Maximum TSID used by EDCA. EDCA uses 0~7; HCCA uses 8~15 */
-#define EDCA_TSID_MIN 0
-#define EDCA_TSID_MAX 7
-
 struct ieee80211_fragment_entry {
        unsigned long first_frag_time;
        unsigned int seq;
@@ -94,8 +91,6 @@ struct ieee80211_sta_bss {
        size_t rsn_ie_len;
        u8 *wmm_ie;
        size_t wmm_ie_len;
-       u8 *ht_ie;
-       size_t ht_ie_len;
 #define IEEE80211_MAX_SUPP_RATES 32
        u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
        size_t supp_rates_len;
@@ -105,6 +100,12 @@ struct ieee80211_sta_bss {
        int probe_resp;
        unsigned long last_update;
 
+       /* during assocation, we save an ERP value from a probe response so
+        * that we can feed ERP info to the driver when handling the
+        * association completes. these fields probably won't be up-to-date
+        * otherwise, you probably don't want to use them. */
+       int has_erp_value;
+       u8 erp_value;
 };
 
 
@@ -112,6 +113,16 @@ typedef enum {
        TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
 } ieee80211_txrx_result;
 
+/* flags used in struct ieee80211_txrx_data.flags */
+/* whether the MSDU was fragmented */
+#define IEEE80211_TXRXD_FRAGMENTED             BIT(0)
+#define IEEE80211_TXRXD_TXUNICAST              BIT(1)
+#define IEEE80211_TXRXD_TXPS_BUFFERED          BIT(2)
+#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG      BIT(3)
+#define IEEE80211_TXRXD_RXIN_SCAN              BIT(4)
+/* frame is destined to interface currently processed (incl. multicast frames) */
+#define IEEE80211_TXRXD_RXRA_MATCH             BIT(5)
+#define IEEE80211_TXRXD_TX_INJECTED            BIT(6)
 struct ieee80211_txrx_data {
        struct sk_buff *skb;
        struct net_device *dev;
@@ -120,14 +131,10 @@ struct ieee80211_txrx_data {
        struct sta_info *sta;
        u16 fc, ethertype;
        struct ieee80211_key *key;
-       unsigned int fragmented:1; /* whether the MSDU was fragmented */
+       unsigned int flags;
        union {
                struct {
                        struct ieee80211_tx_control *control;
-                       unsigned int unicast:1;
-                       unsigned int ps_buffered:1;
-                       unsigned int short_preamble:1;
-                       unsigned int probe_last_frag:1;
                        struct ieee80211_hw_mode *mode;
                        struct ieee80211_rate *rate;
                        /* use this rate (if set) for last fragment; rate can
@@ -135,7 +142,6 @@ struct ieee80211_txrx_data {
                         * when using CTS protection with IEEE 802.11g. */
                        struct ieee80211_rate *last_frag_rate;
                        int last_frag_hwrate;
-                       int mgmt_interface;
 
                        /* Extra fragments (in addition to the first fragment
                         * in skb) */
@@ -147,28 +153,22 @@ struct ieee80211_txrx_data {
                        int sent_ps_buffered;
                        int queue;
                        int load;
-                       u16 qos_control;
-                       unsigned int in_scan:1;
-                       /* frame is destined to interface currently processed
-                        * (including multicast frames) */
-                       unsigned int ra_match:1;
-                       unsigned int is_agg_frame:1;
+                       u32 tkip_iv32;
+                       u16 tkip_iv16;
                } rx;
        } u;
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       int wpa_test;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
 };
 
+/* flags used in struct ieee80211_tx_packet_data.flags */
+#define IEEE80211_TXPD_REQ_TX_STATUS   BIT(0)
+#define IEEE80211_TXPD_DO_NOT_ENCRYPT  BIT(1)
+#define IEEE80211_TXPD_REQUEUE         BIT(2)
 /* Stored in sk_buff->cb */
 struct ieee80211_tx_packet_data {
        int ifindex;
        unsigned long jiffies;
-       unsigned int req_tx_status:1;
-       unsigned int do_not_encrypt:1;
-       unsigned int requeue:1;
-       unsigned int mgmt_iface:1;
-       unsigned int queue:4;
+       unsigned int flags;
+       u8 queue;
 };
 
 struct ieee80211_tx_stored_packet {
@@ -179,20 +179,7 @@ struct ieee80211_tx_stored_packet {
        int last_frag_rateidx;
        int last_frag_hwrate;
        struct ieee80211_rate *last_frag_rate;
-       unsigned int last_frag_rate_ctrl_probe:1;
-};
-
-struct sta_ts_data {
-       enum {
-               TS_STATUS_UNUSED        = 0,
-               TS_STATUS_ACTIVE        = 1,
-               TS_STATUS_INACTIVE      = 2,
-               TS_STATUS_THROTTLING    = 3,
-       } status;
-       u8 dialog_token;
-       u8 up;
-       u32 admitted_time_usec;
-       u32 used_time_usec;
+       unsigned int last_frag_rate_ctrl_probe;
 };
 
 typedef ieee80211_txrx_result (*ieee80211_tx_handler)
@@ -205,10 +192,10 @@ struct ieee80211_if_ap {
        u8 *beacon_head, *beacon_tail;
        int beacon_head_len, beacon_tail_len;
 
+       struct list_head vlans;
+
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        size_t ssid_len;
-       u8 *generic_elem;
-       size_t generic_elem_len;
 
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
@@ -228,9 +215,23 @@ struct ieee80211_if_wds {
 };
 
 struct ieee80211_if_vlan {
-       u8 id;
+       struct ieee80211_sub_if_data *ap;
+       struct list_head list;
 };
 
+/* flags used in struct ieee80211_if_sta.flags */
+#define IEEE80211_STA_SSID_SET         BIT(0)
+#define IEEE80211_STA_BSSID_SET                BIT(1)
+#define IEEE80211_STA_PREV_BSSID_SET   BIT(2)
+#define IEEE80211_STA_AUTHENTICATED    BIT(3)
+#define IEEE80211_STA_ASSOCIATED       BIT(4)
+#define IEEE80211_STA_PROBEREQ_POLL    BIT(5)
+#define IEEE80211_STA_CREATE_IBSS      BIT(6)
+#define IEEE80211_STA_MIXED_CELL       BIT(7)
+#define IEEE80211_STA_WMM_ENABLED      BIT(8)
+#define IEEE80211_STA_AUTO_SSID_SEL    BIT(10)
+#define IEEE80211_STA_AUTO_BSSID_SEL   BIT(11)
+#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
 struct ieee80211_if_sta {
        enum {
                IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
@@ -239,7 +240,6 @@ struct ieee80211_if_sta {
        } state;
        struct timer_list timer;
        struct work_struct work;
-       struct timer_list admit_timer; /* Recompute EDCA admitted time */
        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        size_t ssid_len;
@@ -254,27 +254,14 @@ struct ieee80211_if_sta {
 
        int auth_tries, assoc_tries;
 
-       unsigned int ssid_set:1;
-       unsigned int bssid_set:1;
-       unsigned int prev_bssid_set:1;
-       unsigned int authenticated:1;
-       unsigned int associated:1;
-       unsigned int probereq_poll:1;
-       unsigned int use_protection:1;
-       unsigned int create_ibss:1;
-       unsigned int mixed_cell:1;
-       unsigned int wmm_enabled:1;
-       unsigned int ht_enabled:1;
-       unsigned int auto_ssid_sel:1;
-       unsigned int auto_bssid_sel:1;
-       unsigned int auto_channel_sel:1;
+       unsigned int flags;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
        unsigned long request;
        struct sk_buff_head skb_queue;
 
-       int key_mgmt;
+       int key_management_enabled;
        unsigned long last_probe;
 
 #define IEEE80211_AUTH_ALG_OPEN BIT(0)
@@ -289,34 +276,32 @@ struct ieee80211_if_sta {
        u32 supp_rates_bits;
 
        int wmm_last_param_set;
-
-       u32 dot11EDCAAveragingPeriod;
-       u32 MPDUExchangeTime;
-#define STA_TSID_NUM   16
-#define STA_TSDIR_NUM  2
-       /* EDCA: 0~7, HCCA: 8~15 */
-       struct sta_ts_data ts_data[STA_TSID_NUM][STA_TSDIR_NUM];
-#ifdef CONFIG_MAC80211_DEBUGFS
-       struct ieee80211_elem_tspec tspec;
-       u8 dls_mac[ETH_ALEN];
-#endif
 };
 
 
+/* flags used in struct ieee80211_sub_if_data.flags */
+#define IEEE80211_SDATA_ALLMULTI       BIT(0)
+#define IEEE80211_SDATA_PROMISC                BIT(1)
+#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */
+/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon
+ * generator reports that there are no present stations that cannot support short
+ * preambles */
+#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3)
+#define IEEE80211_SDATA_USERSPACE_MLME BIT(4)
 struct ieee80211_sub_if_data {
        struct list_head list;
-       unsigned int type;
+       enum ieee80211_if_types type;
 
        struct wireless_dev wdev;
 
+       /* keys */
+       struct list_head key_list;
+
        struct net_device *dev;
        struct ieee80211_local *local;
 
-       int mc_count;
-       unsigned int allmulti:1;
-       unsigned int promisc:1;
+       unsigned int flags;
 
-       struct net_device_stats stats;
        int drop_unencrypted;
        int eapol; /* 0 = process EAPOL frames as normal data frames,
                    * 1 = send EAPOL frames through wlan#ap to hostapd
@@ -367,39 +352,6 @@ struct ieee80211_sub_if_data {
                        struct dentry *auth_alg;
                        struct dentry *auth_transaction;
                        struct dentry *flags;
-                       struct dentry *qos_dir;
-                       struct {
-                               struct dentry *addts_11e;
-                               struct dentry *addts_wmm;
-                               struct dentry *delts_11e;
-                               struct dentry *delts_wmm;
-                               struct dentry *dls_mac;
-                               struct dentry *dls_op;
-                       } qos;
-                       struct dentry *tsinfo_dir;
-                       struct {
-                               struct dentry *tsid;
-                               struct dentry *direction;
-                               struct dentry *up;
-                       } tsinfo;
-                       struct dentry *tspec_dir;
-                       struct {
-                               struct dentry *nominal_msdu_size;
-                               struct dentry *max_msdu_size;
-                               struct dentry *min_service_interval;
-                               struct dentry *max_service_interval;
-                               struct dentry *inactivity_interval;
-                               struct dentry *suspension_interval;
-                               struct dentry *service_start_time;
-                               struct dentry *min_data_rate;
-                               struct dentry *mean_data_rate;
-                               struct dentry *peak_data_rate;
-                               struct dentry *burst_size;
-                               struct dentry *delay_bound;
-                               struct dentry *min_phy_rate;
-                               struct dentry *surplus_band_allow;
-                               struct dentry *medium_time;
-                       } tspec;
                } sta;
                struct {
                        struct dentry *channel_use;
@@ -428,7 +380,6 @@ struct ieee80211_sub_if_data {
                        struct dentry *drop_unencrypted;
                        struct dentry *eapol;
                        struct dentry *ieee8021_x;
-                       struct dentry *vlan_id;
                } vlan;
                struct {
                        struct dentry *mode;
@@ -457,11 +408,12 @@ struct ieee80211_local {
        struct list_head modes_list;
 
        struct net_device *mdev; /* wmaster# - "master" 802.11 device */
-       struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
        int open_count;
        int monitors;
+       unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
        u8 wstats_flags;
+       int tx_headroom; /* required headroom for hardware/radiotap */
 
        enum {
                IEEE80211_DEV_UNINITIALIZED = 0,
@@ -479,10 +431,9 @@ struct ieee80211_local {
        struct sk_buff_head skb_queue_unreliable;
 
        /* Station data structures */
-       spinlock_t sta_lock; /* mutex for STA data structures */
+       rwlock_t sta_lock; /* protects STA data structures */
        int num_sta; /* number of stations in sta_list */
        struct list_head sta_list;
-       struct list_head deleted_sta_list;
        struct sta_info *sta_hash[STA_HASH_SIZE];
        struct timer_list sta_cleanup;
 
@@ -490,35 +441,24 @@ struct ieee80211_local {
        struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
 
-       int mc_count;   /* total count of multicast entries in all interfaces */
-       int iff_allmultis, iff_promiscs;
-                       /* number of interfaces with corresponding IFF_ flags */
+       /* number of interfaces with corresponding IFF_ flags */
+       atomic_t iff_allmultis, iff_promiscs;
 
        struct rate_control_ref *rate_ctrl;
 
-       int next_mode; /* MODE_IEEE80211*
-                       * The mode preference for next channel change. This is
-                       * used to select .11g vs. .11b channels (or 4.9 GHz vs.
-                       * .11a) when the channel number is not unique. */
-
        /* Supported and basic rate filters for different modes. These are
         * pointers to -1 terminated lists and rates in 100 kbps units. */
        int *supp_rates[NUM_IEEE80211_MODES];
        int *basic_rates[NUM_IEEE80211_MODES];
 
        int rts_threshold;
-       int cts_protect_erp_frames;
        int fragmentation_threshold;
        int short_retry_limit; /* dot11ShortRetryLimit */
        int long_retry_limit; /* dot11LongRetryLimit */
-       int short_preamble; /* use short preamble with IEEE 802.11b */
 
        struct crypto_blkcipher *wep_tx_tfm;
        struct crypto_blkcipher *wep_rx_tfm;
        u32 wep_iv;
-       int key_tx_rx_threshold; /* number of times any key can be used in TX
-                                 * or RX before generating a rekey
-                                 * notification; 0 = notification disabled. */
 
        int bridge_packets; /* bridge packets between associated stations and
                             * deliver multicast frames both back to wireless
@@ -528,9 +468,8 @@ struct ieee80211_local {
        ieee80211_rx_handler *rx_handlers;
        ieee80211_tx_handler *tx_handlers;
 
-       rwlock_t sub_if_lock; /* Protects sub_if_list. Cannot be taken under
-                              * sta_bss_lock or sta_lock. */
-       struct list_head sub_if_list;
+       struct list_head interfaces;
+
        int sta_scanning;
        int scan_channel_idx;
        enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
@@ -549,9 +488,6 @@ struct ieee80211_local {
 #define IEEE80211_SCAN_EXTRA_INFO BIT(2)
        int scan_flags;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       u32 wpa_trigger;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
        /* SNMP counters */
        /* dot11CountersTable */
        u32 dot11TransmittedFragmentCount;
@@ -567,27 +503,17 @@ struct ieee80211_local {
 
 #ifdef CONFIG_MAC80211_LEDS
        int tx_led_counter, rx_led_counter;
-       struct led_trigger *tx_led, *rx_led;
-       char tx_led_name[32], rx_led_name[32];
+       struct led_trigger *tx_led, *rx_led, *assoc_led;
+       char tx_led_name[32], rx_led_name[32], assoc_led_name[32];
 #endif
 
        u32 channel_use;
        u32 channel_use_raw;
-       u32 stat_time;
-       struct timer_list stat_timer;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct work_struct sta_debugfs_add;
 #endif
 
-       enum {
-               STA_ANTENNA_SEL_AUTO = 0,
-               STA_ANTENNA_SEL_SW_CTRL = 1,
-               STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2
-       } sta_antenna_sel;
-
-       int rate_ctrl_num_up, rate_ctrl_num_down;
-
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
        /* TX/RX handler statistics */
        unsigned int tx_handlers_drop;
@@ -617,16 +543,9 @@ struct ieee80211_local {
 #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
 
 
-       int default_wep_only; /* only default WEP keys are used with this
-                              * interface; this is used to decide when hwaccel
-                              * can be used with default keys */
        int total_ps_buffered; /* total number of all buffered unicast and
                                * multicast packets for power saving stations
                                */
-       int allow_broadcast_always; /* whether to allow TX of broadcast frames
-                                    * even when there are no associated STAs
-                                    */
-
        int wifi_wme_noack_test;
        unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
@@ -635,17 +554,13 @@ struct ieee80211_local {
        unsigned int hw_modes; /* bitfield of supported hardware modes;
                                * (1 << MODE_*) */
 
-       int user_space_mlme;
-
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct local_debugfsdentries {
                struct dentry *channel;
                struct dentry *frequency;
-               struct dentry *radar_detect;
                struct dentry *antenna_sel_tx;
                struct dentry *antenna_sel_rx;
                struct dentry *bridge_packets;
-               struct dentry *key_tx_rx_threshold;
                struct dentry *rts_threshold;
                struct dentry *fragmentation_threshold;
                struct dentry *short_retry_limit;
@@ -653,8 +568,6 @@ struct ieee80211_local {
                struct dentry *total_ps_buffered;
                struct dentry *mode;
                struct dentry *wep_iv;
-               struct dentry *rate_ctrl_alg;
-               struct dentry *tx_power_reduction;
                struct dentry *modes;
                struct dentry *statistics;
                struct local_debugfsdentries_statsdentries {
@@ -703,11 +616,6 @@ struct ieee80211_local {
 #endif
 };
 
-enum sta_link_direction {
-       STA_TS_UPLINK = 0,
-       STA_TS_DOWNLINK = 1,
-};
-
 static inline struct ieee80211_local *hw_to_local(
        struct ieee80211_hw *hw)
 {
@@ -731,38 +639,38 @@ struct sta_attribute {
        ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
 };
 
-static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid)
+static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
 {
        /*
-        * This format has ben mandated by the IEEE specifications,
+        * This format has been mandated by the IEEE specifications,
         * so this line may not be changed to use the __set_bit() format.
         */
-       bss->tim[(aid)/8] |= 1<<((aid) % 8);
+       bss->tim[aid / 8] |= (1 << (aid % 8));
 }
 
 static inline void bss_tim_set(struct ieee80211_local *local,
-                              struct ieee80211_if_ap *bss, int aid)
+                              struct ieee80211_if_ap *bss, u16 aid)
 {
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        __bss_tim_set(bss, aid);
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
 }
 
-static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
+static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
 {
        /*
-        * This format has ben mandated by the IEEE specifications,
+        * This format has been mandated by the IEEE specifications,
         * so this line may not be changed to use the __clear_bit() format.
         */
-       bss->tim[(aid)/8] &= !(1<<((aid) % 8));
+       bss->tim[aid / 8] &= ~(1 << (aid % 8));
 }
 
 static inline void bss_tim_clear(struct ieee80211_local *local,
-                                struct ieee80211_if_ap *bss, int aid)
+                                struct ieee80211_if_ap *bss, u16 aid)
 {
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        __bss_tim_clear(bss, aid);
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
 }
 
 /**
@@ -782,38 +690,28 @@ static inline int ieee80211_is_erp_rate(int phymode, int rate)
        return 0;
 }
 
+static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
+{
+       return compare_ether_addr(raddr, addr) == 0 ||
+              is_broadcast_ether_addr(raddr);
+}
+
+
 /* ieee80211.c */
 int ieee80211_hw_config(struct ieee80211_local *local);
 int ieee80211_if_config(struct net_device *dev);
 int ieee80211_if_config_beacon(struct net_device *dev);
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-                       const struct ieee80211_key *data);
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-                                         int idx, size_t key_len, gfp_t flags);
-void ieee80211_key_free(struct ieee80211_key *key);
-void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
-                      struct ieee80211_rx_status *status, u32 msg_type);
 void ieee80211_prepare_rates(struct ieee80211_local *local,
                             struct ieee80211_hw_mode *mode);
 void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
 int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
 void ieee80211_if_setup(struct net_device *dev);
-void ieee80211_if_mgmt_setup(struct net_device *dev);
-int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
-                                const char *name);
-struct net_device_stats *ieee80211_dev_stats(struct net_device *dev);
+struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
+                                         int phymode, int hwrate);
 
 /* ieee80211_ioctl.c */
-int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 extern const struct iw_handler_def ieee80211_iw_handler_def;
 
-/* Set hw encryption from ieee80211 */
-int ieee80211_set_hw_encryption(struct net_device *dev,
-                               struct sta_info *sta, u8 addr[ETH_ALEN],
-                               struct ieee80211_key *key);
-void ieee80211_update_default_wep_only(struct ieee80211_local *local);
-
 
 /* Least common multiple of the used rates (in 100 kbps). This is used to
  * calculate rate_inv values for each rate so that only integers are needed. */
@@ -841,7 +739,6 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
 /* ieee80211_sta.c */
 void ieee80211_sta_timer(unsigned long data);
 void ieee80211_sta_work(struct work_struct *work);
-void ieee80211_admit_refresh(unsigned long ptr);
 void ieee80211_sta_scan_work(struct work_struct *work);
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
                           struct ieee80211_rx_status *rx_status);
@@ -862,28 +759,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
                                         u8 *addr);
 int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
 int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
-void ieee80211_send_addts(struct net_device *dev,
-                         struct ieee80211_if_sta *ifsta,
-                         struct ieee80211_elem_tspec *tspec);
-void wmm_send_addts(struct net_device *dev,
-                   struct ieee80211_if_sta *ifsta,
-                   struct ieee80211_elem_tspec *tspec);
-void ieee80211_send_delts(struct net_device *dev,
-                         struct ieee80211_if_sta *ifsta,
-                         struct ieee80211_elem_tspec *tp);
-void wmm_send_delts(struct net_device *dev,
-                   struct ieee80211_if_sta *ifsta,
-                   struct ieee80211_elem_tspec *tp);
-void ieee80211_send_dls_req(struct net_device *dev,
-                           struct ieee80211_if_sta *ifsta,
-                           u8 *addr, u16 timeout);
-void ieee80211_send_dls_teardown(struct net_device *dev,
-                                struct ieee80211_if_sta *ifsta,
-                                u8 *mac, u16 reason);
-struct sta_info *dls_info_get(struct ieee80211_local *local, u8 *addr);
-void dls_info_add(struct ieee80211_if_sta *ifsta, struct sta_info *dls);
-void dls_info_stop(struct ieee80211_if_sta *ifsta);
-int dls_link_status(struct ieee80211_local *local, u8 *addr);
+void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes);
+void ieee80211_reset_erp_info(struct net_device *dev);
 
 /* ieee80211_iface.c */
 int ieee80211_if_add(struct net_device *dev, const char *name,
@@ -895,14 +772,32 @@ void __ieee80211_if_del(struct ieee80211_local *local,
 int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
 void ieee80211_if_free(struct net_device *dev);
 void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
-int ieee80211_if_add_mgmt(struct ieee80211_local *local);
-void ieee80211_if_del_mgmt(struct ieee80211_local *local);
 
 /* regdomain.c */
 void ieee80211_regdomain_init(void);
 void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
 
-/* for wiphy privid */
-extern void *mac80211_wiphy_privid;
+/* rx handling */
+extern ieee80211_rx_handler ieee80211_rx_pre_handlers[];
+extern ieee80211_rx_handler ieee80211_rx_handlers[];
+
+/* tx handling */
+extern ieee80211_tx_handler ieee80211_tx_handlers[];
+void ieee80211_clear_tx_pending(struct ieee80211_local *local);
+void ieee80211_tx_pending(unsigned long data);
+int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* utility functions/constants */
+extern void *mac80211_wiphy_privid; /* for wiphy privid */
+extern const unsigned char rfc1042_header[6];
+extern const unsigned char bridge_tunnel_header[6];
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
+int ieee80211_is_eapol(const struct sk_buff *skb);
+int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+                            int rate, int erp, int short_preamble);
+void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
+                                    struct ieee80211_hdr *hdr);
 
 #endif /* IEEE80211_I_H */
index 683d2751c26caec775b6f925362e5226b79a34ea..43e505d294527ca1769c24da69b82c7b42ee6e66 100644 (file)
@@ -25,6 +25,8 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
        sdata->eapol = 1;
        for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
                skb_queue_head_init(&sdata->fragments[i].skb_list);
+
+       INIT_LIST_HEAD(&sdata->key_list);
 }
 
 static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
@@ -77,18 +79,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
        ieee80211_debugfs_add_netdev(sdata);
        ieee80211_if_set_type(ndev, type);
 
-       write_lock_bh(&local->sub_if_lock);
+       /* we're under RTNL so all this is fine */
        if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
-               write_unlock_bh(&local->sub_if_lock);
                __ieee80211_if_del(local, sdata);
                return -ENODEV;
        }
-       list_add(&sdata->list, &local->sub_if_list);
+       list_add_tail_rcu(&sdata->list, &local->interfaces);
+
        if (new_dev)
                *new_dev = ndev;
-       write_unlock_bh(&local->sub_if_lock);
-
-       ieee80211_update_default_wep_only(local);
 
        return 0;
 
@@ -97,72 +96,35 @@ fail:
        return ret;
 }
 
-int ieee80211_if_add_mgmt(struct ieee80211_local *local)
-{
-       struct net_device *ndev;
-       struct ieee80211_sub_if_data *nsdata;
-       int ret;
-
-       ASSERT_RTNL();
-
-       ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
-                           ieee80211_if_mgmt_setup);
-       if (!ndev)
-               return -ENOMEM;
-       ret = dev_alloc_name(ndev, ndev->name);
-       if (ret < 0)
-               goto fail;
-
-       memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-       SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-
-       nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
-       ndev->ieee80211_ptr = &nsdata->wdev;
-       nsdata->wdev.wiphy = local->hw.wiphy;
-       nsdata->type = IEEE80211_IF_TYPE_MGMT;
-       nsdata->dev = ndev;
-       nsdata->local = local;
-       ieee80211_if_sdata_init(nsdata);
-
-       ret = register_netdevice(ndev);
-       if (ret)
-               goto fail;
-
-       ieee80211_debugfs_add_netdev(nsdata);
-
-       if (local->open_count > 0)
-               dev_open(ndev);
-       local->apdev = ndev;
-       return 0;
-
-fail:
-       free_netdev(ndev);
-       return ret;
-}
-
-void ieee80211_if_del_mgmt(struct ieee80211_local *local)
-{
-       struct net_device *apdev;
-
-       ASSERT_RTNL();
-       apdev = local->apdev;
-       ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
-       local->apdev = NULL;
-       unregister_netdevice(apdev);
-}
-
 void ieee80211_if_set_type(struct net_device *dev, int type)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        int oldtype = sdata->type;
 
+       /*
+        * We need to call this function on the master interface
+        * which already has a hard_start_xmit routine assigned
+        * which must not be changed.
+        */
+       if (dev != sdata->local->mdev)
+               dev->hard_start_xmit = ieee80211_subif_start_xmit;
+
+       /*
+        * Called even when register_netdevice fails, it would
+        * oops if assigned before initialising the rest.
+        */
+       dev->uninit = ieee80211_if_reinit;
+
+       /* most have no BSS pointer */
+       sdata->bss = NULL;
        sdata->type = type;
+
        switch (type) {
        case IEEE80211_IF_TYPE_WDS:
-               sdata->bss = NULL;
+               /* nothing special */
                break;
        case IEEE80211_IF_TYPE_VLAN:
+               sdata->u.vlan.ap = NULL;
                break;
        case IEEE80211_IF_TYPE_AP:
                sdata->u.ap.dtim_period = 2;
@@ -170,6 +132,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
                sdata->u.ap.max_ratectrl_rateidx = -1;
                skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
                sdata->bss = &sdata->u.ap;
+               INIT_LIST_HEAD(&sdata->u.ap.vlans);
                break;
        case IEEE80211_IF_TYPE_STA:
        case IEEE80211_IF_TYPE_IBSS: {
@@ -182,30 +145,13 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
                            (unsigned long) sdata);
                skb_queue_head_init(&ifsta->skb_queue);
 
-               init_timer(&ifsta->admit_timer);
-               ifsta->admit_timer.data = (unsigned long) dev;
-               ifsta->admit_timer.function = ieee80211_admit_refresh;
-
                ifsta->capab = WLAN_CAPABILITY_ESS;
                ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
                        IEEE80211_AUTH_ALG_SHARED_KEY;
-               ifsta->create_ibss = 1;
-               ifsta->wmm_enabled = 1;
-               ifsta->ht_enabled = 1;
-               ifsta->auto_channel_sel = 1;
-               ifsta->auto_bssid_sel = 1;
-
-               /* Initialize non-AP QSTA QoS Params */
-               ifsta->dot11EDCAAveragingPeriod = 5;
-               ifsta->MPDUExchangeTime = 0;
-#ifdef CONFIG_MAC80211_DEBUGFS
-               ifsta->tspec.nominal_msdu_size = cpu_to_le16(200),
-               ifsta->tspec.inactivity_interval = cpu_to_le32(40),
-               ifsta->tspec.mean_data_rate = cpu_to_le32(40000),
-               ifsta->tspec.min_phy_rate = cpu_to_le32(6000000),
-               ifsta->tspec.surplus_band_allow = cpu_to_le16(8192),
-               ifsta->tspec.medium_time = cpu_to_le16(30),
-#endif
+               ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+                       IEEE80211_STA_WMM_ENABLED |
+                       IEEE80211_STA_AUTO_BSSID_SEL |
+                       IEEE80211_STA_AUTO_CHANNEL_SEL;
 
                msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
                sdata->bss = &msdata->u.ap;
@@ -213,13 +159,13 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
        }
        case IEEE80211_IF_TYPE_MNTR:
                dev->type = ARPHRD_IEEE80211_RADIOTAP;
+               dev->hard_start_xmit = ieee80211_monitor_start_xmit;
                break;
        default:
                printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
                       dev->name, __FUNCTION__, type);
        }
        ieee80211_debugfs_change_if_type(sdata, oldtype);
-       ieee80211_update_default_wep_only(local);
 }
 
 /* Must be called with rtnl lock held. */
@@ -228,57 +174,46 @@ void ieee80211_if_reinit(struct net_device *dev)
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
-       int i;
+       struct sk_buff *skb;
 
        ASSERT_RTNL();
+
+       ieee80211_free_keys(sdata);
+
        ieee80211_if_sdata_deinit(sdata);
-       for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
-               if (!sdata->keys[i])
-                       continue;
-#if 0
-               /* The interface is down at the moment, so there is not
-                * really much point in disabling the keys at this point. */
-               memset(addr, 0xff, ETH_ALEN);
-               if (local->ops->set_key)
-                       local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
-                                           local->keys[i], 0);
-#endif
-               ieee80211_key_free(sdata->keys[i]);
-               sdata->keys[i] = NULL;
-       }
 
        switch (sdata->type) {
+       case IEEE80211_IF_TYPE_INVALID:
+               /* cannot happen */
+               WARN_ON(1);
+               break;
        case IEEE80211_IF_TYPE_AP: {
                /* Remove all virtual interfaces that use this BSS
                 * as their sdata->bss */
                struct ieee80211_sub_if_data *tsdata, *n;
-               LIST_HEAD(tmp_list);
 
-               write_lock_bh(&local->sub_if_lock);
-               list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
+               list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
                        if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
                                printk(KERN_DEBUG "%s: removing virtual "
                                       "interface %s because its BSS interface"
                                       " is being removed\n",
                                       sdata->dev->name, tsdata->dev->name);
-                               list_move_tail(&tsdata->list, &tmp_list);
+                               list_del_rcu(&tsdata->list);
+                               /*
+                                * We have lots of time and can afford
+                                * to sync for each interface
+                                */
+                               synchronize_rcu();
+                               __ieee80211_if_del(local, tsdata);
                        }
                }
-               write_unlock_bh(&local->sub_if_lock);
-
-               list_for_each_entry_safe(tsdata, n, &tmp_list, list)
-                       __ieee80211_if_del(local, tsdata);
 
                kfree(sdata->u.ap.beacon_head);
                kfree(sdata->u.ap.beacon_tail);
-               kfree(sdata->u.ap.generic_elem);
 
-               if (dev != local->mdev) {
-                       struct sk_buff *skb;
-                       while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-                               local->total_ps_buffered--;
-                               dev_kfree_skb(skb);
-                       }
+               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+                       local->total_ps_buffered--;
+                       dev_kfree_skb(skb);
                }
 
                break;
@@ -286,8 +221,8 @@ void ieee80211_if_reinit(struct net_device *dev)
        case IEEE80211_IF_TYPE_WDS:
                sta = sta_info_get(local, sdata->u.wds.remote_addr);
                if (sta) {
+                       sta_info_free(sta);
                        sta_info_put(sta);
-                       sta_info_free(sta, 0);
                } else {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        printk(KERN_DEBUG "%s: Someone had deleted my STA "
@@ -312,6 +247,9 @@ void ieee80211_if_reinit(struct net_device *dev)
        case IEEE80211_IF_TYPE_MNTR:
                dev->type = ARPHRD_ETHER;
                break;
+       case IEEE80211_IF_TYPE_VLAN:
+               sdata->u.vlan.ap = NULL;
+               break;
        }
 
        /* remove all STAs that are bound to this virtual interface */
@@ -341,29 +279,23 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
 
        ASSERT_RTNL();
 
-       write_lock_bh(&local->sub_if_lock);
-       list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+       list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
                if ((sdata->type == id || id == -1) &&
                    strcmp(name, sdata->dev->name) == 0 &&
                    sdata->dev != local->mdev) {
-                       list_del(&sdata->list);
-                       write_unlock_bh(&local->sub_if_lock);
+                       list_del_rcu(&sdata->list);
+                       synchronize_rcu();
                        __ieee80211_if_del(local, sdata);
-                       ieee80211_update_default_wep_only(local);
                        return 0;
                }
        }
-       write_unlock_bh(&local->sub_if_lock);
        return -ENODEV;
 }
 
 void ieee80211_if_free(struct net_device *dev)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       /* local->apdev must be NULL when freeing management interface */
-       BUG_ON(dev == local->apdev);
        ieee80211_if_sdata_deinit(sdata);
        free_netdev(dev);
 }
index fcea8b28834d361aaf32f6e7e81ea23d3a43ef7b..f95d488726b59cc06cebaf88b4b97fbaf9908e47 100644 (file)
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "hostapd_ioctl.h"
 #include "ieee80211_rate.h"
 #include "wpa.h"
 #include "aes_ccm.h"
-#include "debugfs_key.h"
 
 
-static int ieee80211_ioctl_set_beacon(struct net_device *dev,
-                                     struct prism2_hostapd_param *param,
-                                     int param_len,
-                                     int flag)
+static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
+                                   int idx, int alg, int remove,
+                                   int set_tx_key, const u8 *_key,
+                                   size_t key_len)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       int ret = 0;
+       struct sta_info *sta;
+       struct ieee80211_key *key;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_ap *ap;
-       u8 **b_head, **b_tail;
-       int *b_head_len, *b_tail_len;
-       int len;
-
-       len = ((char *) param->u.beacon.data - (char *) param) +
-               param->u.beacon.head_len + param->u.beacon.tail_len;
-
-       if (param_len > len)
-               param_len = len;
-       else if (param_len != len)
-               return -EINVAL;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_AP)
-               return -EINVAL;
-       ap = &sdata->u.ap;
-
-       switch (flag) {
-       case 0:
-               b_head = &ap->beacon_head;
-               b_tail = &ap->beacon_tail;
-               b_head_len = &ap->beacon_head_len;
-               b_tail_len = &ap->beacon_tail_len;
-               break;
-       default:
-               printk(KERN_DEBUG "%s: unknown beacon flag %d\n",
-                      dev->name, flag);
+
+       if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
+               printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
+                      dev->name, idx);
                return -EINVAL;
        }
 
-       kfree(*b_head);
-       kfree(*b_tail);
-       *b_head = NULL;
-       *b_tail = NULL;
+       if (is_broadcast_ether_addr(sta_addr)) {
+               sta = NULL;
+               key = sdata->keys[idx];
+       } else {
+               set_tx_key = 0;
+               /*
+                * According to the standard, the key index of a pairwise
+                * key must be zero. However, some AP are broken when it
+                * comes to WEP key indices, so we work around this.
+                */
+               if (idx != 0 && alg != ALG_WEP) {
+                       printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
+                              "individual key\n", dev->name);
+                       return -EINVAL;
+               }
+
+               sta = sta_info_get(local, sta_addr);
+               if (!sta) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
+                              MAC_FMT "\n",
+                              dev->name, MAC_ARG(sta_addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-       *b_head_len = param->u.beacon.head_len;
-       *b_tail_len = param->u.beacon.tail_len;
+                       return -ENOENT;
+               }
 
-       *b_head = kmalloc(*b_head_len, GFP_KERNEL);
-       if (*b_head)
-               memcpy(*b_head, param->u.beacon.data, *b_head_len);
-       else {
-               printk(KERN_DEBUG "%s: failed to allocate beacon_head\n",
-                      dev->name);
-               return -ENOMEM;
+               key = sta->key;
        }
 
-       if (*b_tail_len > 0) {
-               *b_tail = kmalloc(*b_tail_len, GFP_KERNEL);
-               if (*b_tail)
-                       memcpy(*b_tail, param->u.beacon.data + (*b_head_len),
-                              (*b_tail_len));
-               else {
-                       printk(KERN_DEBUG "%s: failed to allocate "
-                              "beacon_tail\n", dev->name);
-                       return -ENOMEM;
+       if (remove) {
+               ieee80211_key_free(key);
+               key = NULL;
+       } else {
+               /*
+                * Automatically frees any old key if present.
+                */
+               key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
+               if (!key) {
+                       ret = -ENOMEM;
+                       goto err_out;
                }
        }
 
-       return ieee80211_if_config_beacon(dev);
-}
+       if (set_tx_key || (!sta && !sdata->default_key && key))
+               ieee80211_set_default_key(sdata, idx);
 
+       ret = 0;
+ err_out:
+       if (sta)
+               sta_info_put(sta);
+       return ret;
+}
 
-static int ieee80211_ioctl_get_hw_features(struct net_device *dev,
-                                          struct prism2_hostapd_param *param,
-                                          int param_len)
+static int ieee80211_ioctl_siwgenie(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *data, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u8 *pos = param->u.hw_features.data;
-       int left = param_len - (pos - (u8 *) param);
-       int i;
-       struct hostapd_ioctl_hw_modes_hdr *hdr;
-       struct ieee80211_rate_data *rate;
-       struct ieee80211_channel_data *chan;
-       struct ieee80211_hw_mode *mode;
+       struct ieee80211_sub_if_data *sdata;
 
-       param->u.hw_features.flags = 0;
-       if (local->hw.flags & IEEE80211_HW_DATA_NULLFUNC_ACK)
-               param->u.hw_features.flags |= HOSTAP_HW_FLAG_NULLFUNC_OK;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       param->u.hw_features.num_modes = 0;
-       list_for_each_entry(mode, &local->modes_list, list) {
-               int clen, rlen;
-
-               param->u.hw_features.num_modes++;
-               clen = mode->num_channels * sizeof(struct ieee80211_channel_data);
-               rlen = mode->num_rates * sizeof(struct ieee80211_rate_data);
-               if (left < sizeof(*hdr) + clen + rlen)
-                       return -E2BIG;
-               left -= sizeof(*hdr) + clen + rlen;
-
-               hdr = (struct hostapd_ioctl_hw_modes_hdr *) pos;
-               hdr->mode = mode->mode;
-               hdr->num_channels = mode->num_channels;
-               hdr->num_rates = mode->num_rates;
-
-               pos = (u8 *) (hdr + 1);
-               chan = (struct ieee80211_channel_data *) pos;
-               for (i = 0; i < mode->num_channels; i++) {
-                       chan[i].chan = mode->channels[i].chan;
-                       chan[i].freq = mode->channels[i].freq;
-                       chan[i].flag = mode->channels[i].flag;
-               }
-               pos += clen;
+       if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
+               return -EOPNOTSUPP;
 
-               rate = (struct ieee80211_rate_data *) pos;
-               for (i = 0; i < mode->num_rates; i++) {
-                       rate[i].rate = mode->rates[i].rate;
-                       rate[i].flags = mode->rates[i].flags;
-               }
-               pos += rlen;
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
+               if (ret)
+                       return ret;
+               sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
+               ieee80211_sta_req_auth(dev, &sdata->u.sta);
+               return 0;
        }
 
-       return 0;
+       return -EOPNOTSUPP;
 }
 
-static int ieee80211_ioctl_flush(struct net_device *dev,
-                                struct prism2_hostapd_param *param)
+static int ieee80211_ioctl_giwname(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  char *name, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       sta_info_flush(local, NULL);
-       return 0;
-}
-
 
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-struct iapp_layer2_update {
-       u8 da[ETH_ALEN]; /* broadcast */
-       u8 sa[ETH_ALEN]; /* STA addr */
-       __be16 len; /* 6 */
-       u8 dsap; /* 0 */
-       u8 ssap; /* 0 */
-       u8 control;
-       u8 xid_info[3];
-} __attribute__ ((packed));
+       switch (local->hw.conf.phymode) {
+       case MODE_IEEE80211A:
+               strcpy(name, "IEEE 802.11a");
+               break;
+       case MODE_IEEE80211B:
+               strcpy(name, "IEEE 802.11b");
+               break;
+       case MODE_IEEE80211G:
+               strcpy(name, "IEEE 802.11g");
+               break;
+       default:
+               strcpy(name, "IEEE 802.11");
+               break;
+       }
 
-static void ieee80211_send_layer2_update(struct net_device *dev,
-                                        const u8 *addr)
-{
-       struct iapp_layer2_update *msg;
-       struct sk_buff *skb;
-
-       /* Send Level 2 Update Frame to update forwarding tables in layer 2
-        * bridge devices */
-
-       skb = dev_alloc_skb(sizeof(*msg));
-       if (!skb)
-               return;
-       msg = (struct iapp_layer2_update *) skb_put(skb, sizeof(*msg));
-
-       /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
-        * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-
-       memset(msg->da, 0xff, ETH_ALEN);
-       memcpy(msg->sa, addr, ETH_ALEN);
-       msg->len = htons(6);
-       msg->dsap = 0;
-       msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
-       msg->control = 0xaf; /* XID response lsb.1111F101.
-                             * F=0 (no poll command; unsolicited frame) */
-       msg->xid_info[0] = 0x81; /* XID format identifier */
-       msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
-       msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
-
-       skb->dev = dev;
-       skb->protocol = eth_type_trans(skb, dev);
-       memset(skb->cb, 0, sizeof(skb->cb));
-       netif_rx(skb);
+       return 0;
 }
 
 
-static int ieee80211_ioctl_add_sta(struct net_device *dev,
-                                  struct prism2_hostapd_param *param)
+static int ieee80211_ioctl_giwrange(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *data, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-       u32 rates;
-       int i, j;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_hw_mode *mode;
-       int add_key_entry = 1;
+       struct iw_range *range = (struct iw_range *) extra;
+       struct ieee80211_hw_mode *mode = NULL;
+       int c = 0;
 
-       /* Prevent a race with changing the rate control algorithm */
-       if (!netif_running(dev))
-               return -ENETDOWN;
+       data->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
 
-       sta = sta_info_get(local, param->sta_addr);
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 21;
+       range->retry_capa = IW_RETRY_LIMIT;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->min_retry = 0;
+       range->max_retry = 255;
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
 
-       if (!sta) {
-               sta = sta_info_add(local, dev, param->sta_addr, GFP_KERNEL);
-               if (!sta)
-                       return -ENOMEM;
-       }
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;
+       range->num_encoding_sizes = 2;
+       range->max_encoding_tokens = NUM_DEFAULT_KEYS;
 
-       if (sta->dev != dev) {
-               /* Binding STA to a new interface, so remove all references to
-                * the old BSS. */
-               spin_lock_bh(&local->sta_lock);
-               sta_info_remove_aid_ptr(sta);
-               spin_unlock_bh(&local->sta_lock);
-       }
+       range->max_qual.qual = local->hw.max_signal;
+       range->max_qual.level = local->hw.max_rssi;
+       range->max_qual.noise = local->hw.max_noise;
+       range->max_qual.updated = local->wstats_flags;
 
-       /* TODO
-        * We "steal" the device in case someone owns it
-        * This will hurt WDS links and such when we have a
-        * WDS link and a client associating from the same station
-        */
-       sta->dev = dev;
-       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-
-       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
-       sta->aid = param->u.add_sta.aid;
-       if (sta->aid > IEEE80211_MAX_AID)
-               sta->aid = 0;
-       sta->listen_interval = param->u.add_sta.listen_interval;
-
-       rates = 0;
-       mode = local->oper_hw_mode;
-       for (i = 0; i < sizeof(param->u.add_sta.supp_rates); i++) {
-               int rate = (param->u.add_sta.supp_rates[i] & 0x7f) * 5;
-               if (mode->mode == MODE_ATHEROS_TURBO ||
-                   mode->mode == MODE_ATHEROS_TURBOG)
-                       rate *= 2;
-               for (j = 0; j < mode->num_rates; j++) {
-                       if (mode->rates[j].rate == rate)
-                               rates |= BIT(j);
-               }
+       range->avg_qual.qual = local->hw.max_signal/2;
+       range->avg_qual.level = 0;
+       range->avg_qual.noise = 0;
+       range->avg_qual.updated = local->wstats_flags;
 
-       }
-       sta->supp_rates = rates;
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-       rate_control_rate_init(sta, local);
+       list_for_each_entry(mode, &local->modes_list, list) {
+               int i = 0;
 
-       if (param->u.add_sta.wds_flags & 0x01)
-               sta->flags |= WLAN_STA_WDS;
-       else
-               sta->flags &= ~WLAN_STA_WDS;
-
-       if (add_key_entry && !sta->key && !sdata->default_key &&
-           local->ops->set_key) {
-               struct ieee80211_key_conf conf;
-               /* Add key cache entry with NULL key type because this may used
-                * for TX filtering. */
-               memset(&conf, 0, sizeof(conf));
-               conf.hw_key_idx = HW_KEY_IDX_INVALID;
-               conf.alg = ALG_NULL;
-               conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
-               if (local->ops->set_key(local_to_hw(local), SET_KEY,
-                                      sta->addr, &conf, sta->aid)) {
-                       sta->key_idx_compression = HW_KEY_IDX_INVALID;
-               } else {
-                       sta->key_idx_compression = conf.hw_key_idx;
+               if (!(local->enabled_modes & (1 << mode->mode)) ||
+                   (local->hw_modes & local->enabled_modes &
+                    (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+                       continue;
+
+               while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
+                       struct ieee80211_channel *chan = &mode->channels[i];
+
+                       if (chan->flag & IEEE80211_CHAN_W_SCAN) {
+                               range->freq[c].i = chan->chan;
+                               range->freq[c].m = chan->freq * 100000;
+                               range->freq[c].e = 1;
+                               c++;
+                       }
+                       i++;
                }
        }
+       range->num_channels = c;
+       range->num_frequency = c;
 
-       sta_info_put(sta);
-
-       if (sdata->type == IEEE80211_IF_TYPE_AP ||
-           sdata->type == IEEE80211_IF_TYPE_VLAN)
-               ieee80211_send_layer2_update(dev, param->sta_addr);
+       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 
        return 0;
 }
 
 
-static int ieee80211_ioctl_remove_sta(struct net_device *dev,
-                                     struct prism2_hostapd_param *param)
+static int ieee80211_ioctl_siwmode(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  __u32 *mode, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int type;
 
-       sta = sta_info_get(local, param->sta_addr);
-       if (sta) {
-               sta_info_put(sta);
-               sta_info_free(sta, 0);
-       }
+       if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+               return -EOPNOTSUPP;
 
-       return sta ? 0 : -ENOENT;
-}
+       switch (*mode) {
+       case IW_MODE_INFRA:
+               type = IEEE80211_IF_TYPE_STA;
+               break;
+       case IW_MODE_ADHOC:
+               type = IEEE80211_IF_TYPE_IBSS;
+               break;
+       case IW_MODE_MONITOR:
+               type = IEEE80211_IF_TYPE_MNTR;
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       if (type == sdata->type)
+               return 0;
+       if (netif_running(dev))
+               return -EBUSY;
 
-static int ieee80211_ioctl_get_dot11counterstable(struct net_device *dev,
-                                       struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_low_level_stats stats;
-
-       memset(&stats, 0, sizeof(stats));
-       if (local->ops->get_stats)
-               local->ops->get_stats(local_to_hw(local), &stats);
-       param->u.dot11CountersTable.dot11TransmittedFragmentCount =
-               local->dot11TransmittedFragmentCount;
-       param->u.dot11CountersTable.dot11MulticastTransmittedFrameCount =
-               local->dot11MulticastTransmittedFrameCount;
-       param->u.dot11CountersTable.dot11ReceivedFragmentCount =
-               local->dot11ReceivedFragmentCount;
-       param->u.dot11CountersTable.dot11MulticastReceivedFrameCount =
-               local->dot11MulticastReceivedFrameCount;
-       param->u.dot11CountersTable.dot11TransmittedFrameCount =
-               local->dot11TransmittedFrameCount;
-       param->u.dot11CountersTable.dot11FCSErrorCount =
-               stats.dot11FCSErrorCount;
-       param->u.dot11CountersTable.dot11ACKFailureCount =
-               stats.dot11ACKFailureCount;
-       param->u.dot11CountersTable.dot11RTSFailureCount =
-               stats.dot11RTSFailureCount;
-       param->u.dot11CountersTable.dot11RTSSuccessCount =
-               stats.dot11RTSSuccessCount;
+       ieee80211_if_reinit(dev);
+       ieee80211_if_set_type(dev, type);
 
        return 0;
 }
 
 
-static int ieee80211_ioctl_get_info_sta(struct net_device *dev,
-                                       struct prism2_hostapd_param *param)
+static int ieee80211_ioctl_giwmode(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  __u32 *mode, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       struct sta_info *sta;
-
-       if (is_broadcast_ether_addr(param->sta_addr)) {
-               struct net_device_stats *stats;
+       struct ieee80211_sub_if_data *sdata;
 
-               stats = ieee80211_dev_stats(local->mdev);
-               param->u.get_info_sta.rx_bytes = stats->rx_bytes;
-               param->u.get_info_sta.tx_bytes = stats->tx_bytes;
-               /* go through all STAs and get STA with lowest max. rate */
-               param->u.get_info_sta.current_tx_rate =
-                       sta_info_min_txrate_get(local);
-               return 0;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_AP:
+               *mode = IW_MODE_MASTER;
+               break;
+       case IEEE80211_IF_TYPE_STA:
+               *mode = IW_MODE_INFRA;
+               break;
+       case IEEE80211_IF_TYPE_IBSS:
+               *mode = IW_MODE_ADHOC;
+               break;
+       case IEEE80211_IF_TYPE_MNTR:
+               *mode = IW_MODE_MONITOR;
+               break;
+       case IEEE80211_IF_TYPE_WDS:
+               *mode = IW_MODE_REPEAT;
+               break;
+       case IEEE80211_IF_TYPE_VLAN:
+               *mode = IW_MODE_SECOND;         /* FIXME */
+               break;
+       default:
+               *mode = IW_MODE_AUTO;
+               break;
        }
-
-       sta = sta_info_get(local, param->sta_addr);
-
-       if (!sta)
-               return -ENOENT;
-
-       param->u.get_info_sta.inactive_msec =
-               jiffies_to_msecs(jiffies - sta->last_rx);
-       param->u.get_info_sta.rx_packets = sta->rx_packets;
-       param->u.get_info_sta.tx_packets = sta->tx_packets;
-       param->u.get_info_sta.rx_bytes = sta->rx_bytes;
-       param->u.get_info_sta.tx_bytes = sta->tx_bytes;
-       param->u.get_info_sta.channel_use = sta->channel_use;
-       param->u.get_info_sta.flags = sta->flags;
-       mode = local->oper_hw_mode;
-       if (sta->txrate >= 0 && sta->txrate < mode->num_rates)
-               param->u.get_info_sta.current_tx_rate =
-                       mode->rates[sta->txrate].rate;
-       param->u.get_info_sta.num_ps_buf_frames =
-               skb_queue_len(&sta->ps_tx_buf);
-       param->u.get_info_sta.tx_retry_failed = sta->tx_retry_failed;
-       param->u.get_info_sta.tx_retry_count = sta->tx_retry_count;
-       param->u.get_info_sta.last_rssi = sta->last_rssi;
-       param->u.get_info_sta.last_ack_rssi = sta->last_ack_rssi[2];
-
-       sta_info_put(sta);
-
        return 0;
 }
 
-
-static int ieee80211_ioctl_set_flags_sta(struct net_device *dev,
-                                        struct prism2_hostapd_param *param)
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
+       struct ieee80211_hw_mode *mode;
+       int c, set = 0;
+       int ret = -EINVAL;
 
-       sta = sta_info_get(local, param->sta_addr);
-       if (sta) {
-               sta->flags |= param->u.set_flags_sta.flags_or;
-               sta->flags &= param->u.set_flags_sta.flags_and;
-               if (local->ops->set_port_auth &&
-                   (param->u.set_flags_sta.flags_or & WLAN_STA_AUTHORIZED) &&
-                   local->ops->set_port_auth(local_to_hw(local), sta->addr, 1))
-                       printk(KERN_DEBUG "%s: failed to set low-level driver "
-                              "PAE state (authorized) for " MAC_FMT "\n",
-                              dev->name, MAC_ARG(sta->addr));
-               if (local->ops->set_port_auth &&
-                   !(param->u.set_flags_sta.flags_and & WLAN_STA_AUTHORIZED) &&
-                   local->ops->set_port_auth(local_to_hw(local), sta->addr, 0))
-                       printk(KERN_DEBUG "%s: failed to set low-level driver "
-                              "PAE state (unauthorized) for " MAC_FMT "\n",
-                              dev->name, MAC_ARG(sta->addr));
-               sta_info_put(sta);
+       list_for_each_entry(mode, &local->modes_list, list) {
+               if (!(local->enabled_modes & (1 << mode->mode)))
+                       continue;
+               for (c = 0; c < mode->num_channels; c++) {
+                       struct ieee80211_channel *chan = &mode->channels[c];
+                       if (chan->flag & IEEE80211_CHAN_W_SCAN &&
+                           ((chan->chan == channel) || (chan->freq == freq))) {
+                               local->oper_channel = chan;
+                               local->oper_hw_mode = mode;
+                               set++;
+                       }
+               }
        }
 
-       return sta ? 0 : -ENOENT;
-}
-
-
-int ieee80211_set_hw_encryption(struct net_device *dev,
-                               struct sta_info *sta, u8 addr[ETH_ALEN],
-                               struct ieee80211_key *key)
-{
-       struct ieee80211_key_conf *keyconf = NULL;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int rc = 0;
-
-       /* default to sw encryption; this will be cleared by low-level
-        * driver if the hw supports requested encryption */
-       if (key)
-               key->force_sw_encrypt = 1;
-
-       if (key && local->ops->set_key &&
-           (keyconf = ieee80211_key_data2conf(local, key))) {
-               if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
-                                      keyconf, sta ? sta->aid : 0)) {
-                       rc = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
-                       key->force_sw_encrypt = 1;
-                       key->hw_key_idx = HW_KEY_IDX_INVALID;
-               } else {
-                       key->force_sw_encrypt =
-                               !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
-                       key->hw_key_idx =
-                               keyconf->hw_key_idx;
+       if (set) {
+               if (local->sta_scanning)
+                       ret = 0;
+               else
+                       ret = ieee80211_hw_config(local);
 
-               }
+               rate_control_clear(local);
        }
-       kfree(keyconf);
 
-       return rc;
+       return ret;
 }
 
-
-static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
-                                   int idx, int alg, int set_tx_key, u32 *err,
-                                   const u8 *_key, size_t key_len)
+static int ieee80211_ioctl_siwfreq(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_freq *freq, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int ret = 0;
-       struct sta_info *sta;
-       struct ieee80211_key *key, *old_key;
-       int try_hwaccel = 1;
-       struct ieee80211_key_conf *keyconf;
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (is_broadcast_ether_addr(sta_addr)) {
-               sta = NULL;
-               if (idx >= NUM_DEFAULT_KEYS) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
-                              dev->name, idx);
-                       return -EINVAL;
-               }
-               key = sdata->keys[idx];
+       if (sdata->type == IEEE80211_IF_TYPE_STA)
+               sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
-               /* TODO: consider adding hwaccel support for these; at least
-                * Atheros key cache should be able to handle this since AP is
-                * only transmitting frames with default keys. */
-               /* FIX: hw key cache can be used when only one virtual
-                * STA is associated with each AP. If more than one STA
-                * is associated to the same AP, software encryption
-                * must be used. This should be done automatically
-                * based on configured station devices. For the time
-                * being, this can be only set at compile time. */
+       /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
+       if (freq->e == 0) {
+               if (freq->m < 0) {
+                       if (sdata->type == IEEE80211_IF_TYPE_STA)
+                               sdata->u.sta.flags |=
+                                       IEEE80211_STA_AUTO_CHANNEL_SEL;
+                       return 0;
+               } else
+                       return ieee80211_set_channel(local, freq->m, -1);
        } else {
-               set_tx_key = 0;
-               if (idx != 0) {
-                       printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
-                              "individual key\n", dev->name);
+               int i, div = 1000000;
+               for (i = 0; i < freq->e; i++)
+                       div /= 10;
+               if (div > 0)
+                       return ieee80211_set_channel(local, -1, freq->m / div);
+               else
                        return -EINVAL;
-               }
-
-               sta = sta_info_get(local, sta_addr);
-               if (!sta) {
-                       if (err)
-                               *err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
-                              MAC_FMT "\n",
-                              dev->name, MAC_ARG(sta_addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       }
+}
 
-                       return -ENOENT;
-               }
 
-               key = sta->key;
-       }
+static int ieee80211_ioctl_giwfreq(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_freq *freq, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       /* FIX:
-        * Cannot configure default hwaccel keys with WEP algorithm, if
-        * any of the virtual interfaces is using static WEP
-        * configuration because hwaccel would otherwise try to decrypt
-        * these frames.
-        *
-        * For now, just disable WEP hwaccel for broadcast when there is
-        * possibility of conflict with default keys. This can maybe later be
-        * optimized by using non-default keys (at least with Atheros ar521x).
-        */
-       if (!sta && alg == ALG_WEP && !local->default_wep_only &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS &&
-           sdata->type != IEEE80211_IF_TYPE_AP) {
-               try_hwaccel = 0;
-       }
+       /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
+        * driver for the current channel with firmware-based management */
 
-       if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
-               /* Software encryption cannot be used with devices that hide
-                * encryption from the host system, so always try to use
-                * hardware acceleration with such devices. */
-               try_hwaccel = 1;
-       }
+       freq->m = local->hw.conf.freq;
+       freq->e = 6;
 
-       if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
-           alg == ALG_TKIP) {
-               if (sta && (sta->flags & WLAN_STA_WME)) {
-               /* Hardware does not support hwaccel with TKIP when using WMM.
-                */
-                       try_hwaccel = 0;
-               }
-               else if (sdata->type == IEEE80211_IF_TYPE_STA) {
-                       sta = sta_info_get(local, sdata->u.sta.bssid);
-                       if (sta) {
-                               if (sta->flags & WLAN_STA_WME) {
-                                       try_hwaccel = 0;
-                               }
-                               sta_info_put(sta);
-                               sta = NULL;
-                       }
-               }
-       }
+       return 0;
+}
 
-       if (alg == ALG_NONE) {
-               keyconf = NULL;
-               if (try_hwaccel && key &&
-                   key->hw_key_idx != HW_KEY_IDX_INVALID &&
-                   local->ops->set_key &&
-                   (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
-                   local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-                                      sta_addr, keyconf, sta ? sta->aid : 0)) {
-                       if (err)
-                               *err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
-                       printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
-                              " failed\n", dev->name);
-                       ret = -EINVAL;
-               }
-               kfree(keyconf);
 
-               if (set_tx_key || sdata->default_key == key) {
-                       ieee80211_debugfs_key_remove_default(sdata);
-                       sdata->default_key = NULL;
-               }
-               ieee80211_debugfs_key_remove(key);
-               if (sta)
-                       sta->key = NULL;
-               else
-                       sdata->keys[idx] = NULL;
-               ieee80211_key_free(key);
-               key = NULL;
-       } else {
-               old_key = key;
-               key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
-                                         GFP_KERNEL);
-               if (!key) {
-                       ret = -ENOMEM;
-                       goto err_out;
-               }
+static int ieee80211_ioctl_siwessid(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *data, char *ssid)
+{
+       struct ieee80211_sub_if_data *sdata;
+       size_t len = data->length;
 
-               /* default to sw encryption; low-level driver sets these if the
-                * requested encryption is supported */
-               key->hw_key_idx = HW_KEY_IDX_INVALID;
-               key->force_sw_encrypt = 1;
-
-               key->alg = alg;
-               key->keyidx = idx;
-               key->keylen = key_len;
-               memcpy(key->key, _key, key_len);
-               if (set_tx_key)
-                       key->default_tx_key = 1;
-
-               if (alg == ALG_CCMP) {
-                       /* Initialize AES key state here as an optimization
-                        * so that it does not need to be initialized for every
-                        * packet. */
-                       key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
-                               key->key);
-                       if (!key->u.ccmp.tfm) {
-                               ret = -ENOMEM;
-                               goto err_free;
-                       }
-               }
+       /* iwconfig uses nul termination in SSID.. */
+       if (len > 0 && ssid[len - 1] == '\0')
+               len--;
 
-               if (set_tx_key || sdata->default_key == old_key) {
-                       ieee80211_debugfs_key_remove_default(sdata);
-                       sdata->default_key = NULL;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               int ret;
+               if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
+                       if (len > IEEE80211_MAX_SSID_LEN)
+                               return -EINVAL;
+                       memcpy(sdata->u.sta.ssid, ssid, len);
+                       sdata->u.sta.ssid_len = len;
+                       return 0;
                }
-               ieee80211_debugfs_key_remove(old_key);
-               if (sta)
-                       sta->key = key;
+               if (data->flags)
+                       sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
                else
-                       sdata->keys[idx] = key;
-               ieee80211_key_free(old_key);
-               ieee80211_debugfs_key_add(local, key);
-               if (sta)
-                       ieee80211_debugfs_key_sta_link(key, sta);
-
-               if (try_hwaccel &&
-                   (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) {
-                       int e = ieee80211_set_hw_encryption(dev, sta, sta_addr,
-                                                           key);
-                       if (err)
-                               *err = e;
-               }
+                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
+               ret = ieee80211_sta_set_ssid(dev, ssid, len);
+               if (ret)
+                       return ret;
+               ieee80211_sta_req_auth(dev, &sdata->u.sta);
+               return 0;
        }
 
-       if (set_tx_key || (!sta && !sdata->default_key && key)) {
-               sdata->default_key = key;
-               if (key)
-                       ieee80211_debugfs_key_add_default(sdata);
-
-               if (local->ops->set_key_idx &&
-                   local->ops->set_key_idx(local_to_hw(local), idx))
-                       printk(KERN_DEBUG "%s: failed to set TX key idx for "
-                              "low-level driver\n", dev->name);
+       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+               memcpy(sdata->u.ap.ssid, ssid, len);
+               memset(sdata->u.ap.ssid + len, 0,
+                      IEEE80211_MAX_SSID_LEN - len);
+               sdata->u.ap.ssid_len = len;
+               return ieee80211_if_config(dev);
        }
-
-       if (sta)
-               sta_info_put(sta);
-
-       return 0;
-
-err_free:
-       ieee80211_key_free(key);
-err_out:
-       if (sta)
-               sta_info_put(sta);
-       return ret;
+       return -EOPNOTSUPP;
 }
 
 
-static int ieee80211_ioctl_set_encryption(struct net_device *dev,
-                                         struct prism2_hostapd_param *param,
-                                         int param_len)
+static int ieee80211_ioctl_giwessid(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *data, char *ssid)
 {
-       int alg;
-
-       param->u.crypt.err = 0;
-       param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
+       size_t len;
 
-       if (param_len <
-           (int) ((char *) param->u.crypt.key - (char *) param) +
-           param->u.crypt.key_len) {
-               printk(KERN_DEBUG "%s: set_encrypt - invalid param_lem\n",
-                      dev->name);
-               return -EINVAL;
+       struct ieee80211_sub_if_data *sdata;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               int res = ieee80211_sta_get_ssid(dev, ssid, &len);
+               if (res == 0) {
+                       data->length = len;
+                       data->flags = 1;
+               } else
+                       data->flags = 0;
+               return res;
        }
 
-       if (strcmp(param->u.crypt.alg, "none") == 0)
-               alg = ALG_NONE;
-       else if (strcmp(param->u.crypt.alg, "WEP") == 0)
-               alg = ALG_WEP;
-       else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
-               if (param->u.crypt.key_len != ALG_TKIP_KEY_LEN) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid TKIP key "
-                              "length %d\n", dev->name,
-                              param->u.crypt.key_len);
-                       return -EINVAL;
-               }
-               alg = ALG_TKIP;
-       } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
-               if (param->u.crypt.key_len != ALG_CCMP_KEY_LEN) {
-                       printk(KERN_DEBUG "%s: set_encrypt - invalid CCMP key "
-                              "length %d\n", dev->name,
-                              param->u.crypt.key_len);
-                       return -EINVAL;
-               }
-               alg = ALG_CCMP;
-       } else {
-               param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
-               printk(KERN_DEBUG "%s: set_encrypt - unknown alg\n",
-                      dev->name);
-               return -EINVAL;
+       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+               len = sdata->u.ap.ssid_len;
+               if (len > IW_ESSID_MAX_SIZE)
+                       len = IW_ESSID_MAX_SIZE;
+               memcpy(ssid, sdata->u.ap.ssid, len);
+               data->length = len;
+               data->flags = 1;
+               return 0;
        }
-
-       return ieee80211_set_encryption(
-               dev, param->sta_addr,
-               param->u.crypt.idx, alg,
-               param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY,
-               &param->u.crypt.err, param->u.crypt.key,
-               param->u.crypt.key_len);
+       return -EOPNOTSUPP;
 }
 
 
-static int ieee80211_ioctl_get_encryption(struct net_device *dev,
-                                         struct prism2_hostapd_param *param,
-                                         int param_len)
+static int ieee80211_ioctl_siwap(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct sockaddr *ap_addr, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int ret = 0;
-       struct sta_info *sta;
-       struct ieee80211_key **key;
-       int max_key_len;
        struct ieee80211_sub_if_data *sdata;
-       u8 *pos;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       param->u.crypt.err = 0;
-
-       max_key_len = param_len -
-               (int) ((char *) param->u.crypt.key - (char *) param);
-       if (max_key_len < 0)
-               return -EINVAL;
-
-       if (is_broadcast_ether_addr(param->sta_addr)) {
-               sta = NULL;
-               if (param->u.crypt.idx >= NUM_DEFAULT_KEYS) {
-                       param->u.crypt.idx = sdata->default_key ?
-                               sdata->default_key->keyidx : 0;
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               int ret;
+               if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
+                       memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
+                              ETH_ALEN);
                        return 0;
-               } else
-                       key = &sdata->keys[param->u.crypt.idx];
-       } else {
-               sta = sta_info_get(local, param->sta_addr);
-               if (!sta) {
-                       param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
-                       return -EINVAL;
-               }
-
-               key = &sta->key;
-       }
-
-       memset(param->u.crypt.seq_counter, 0, HOSTAP_SEQ_COUNTER_SIZE);
-       if (!*key) {
-               memcpy(param->u.crypt.alg, "none", 5);
-               param->u.crypt.key_len = 0;
-               param->u.crypt.idx = 0xff;
-       } else {
-               switch ((*key)->alg) {
-               case ALG_WEP:
-                       memcpy(param->u.crypt.alg, "WEP", 4);
-                       break;
-               case ALG_TKIP:
-               {
-                       u32 iv32;
-                       u16 iv16;
-
-                       memcpy(param->u.crypt.alg, "TKIP", 5);
-                       if (local->ops->get_sequence_counter) {
-                       /* Get transmit counter from low level driver */
-                               if (local->ops->get_sequence_counter(
-                                               local_to_hw(local),
-                                               param->sta_addr,
-                                               (*key)->keyidx,
-                                               IEEE80211_SEQ_COUNTER_TX,
-                                               &iv32,
-                                               &iv16)) {
-                                       /* Error getting value from device */
-                                       return -EIO;
-                               }
-                       } else {
-                               /* Get it from our own local data */
-                               iv32 = (*key)->u.tkip.iv32;
-                               iv16 = (*key)->u.tkip.iv16;
-                       }
-                       pos = param->u.crypt.seq_counter;
-                       *pos++ = iv16 & 0xff;
-                       *pos++ = (iv16 >> 8) & 0xff;
-                       *pos++ = iv32 & 0xff;
-                       *pos++ = (iv32 >> 8) & 0xff;
-                       *pos++ = (iv32 >> 16) & 0xff;
-                       *pos++ = (iv32 >> 24) & 0xff;
-                       break;
-                       }
-               case ALG_CCMP:
-               {
-                       u8 *pn;
-                       memcpy(param->u.crypt.alg, "CCMP", 5);
-                       pos = param->u.crypt.seq_counter;
-                       pn = (*key)->u.ccmp.tx_pn;
-                       *pos++ = pn[5];
-                       *pos++ = pn[4];
-                       *pos++ = pn[3];
-                       *pos++ = pn[2];
-                       *pos++ = pn[1];
-                       *pos++ = pn[0];
-                       break;
-               }
-               default:
-                       memcpy(param->u.crypt.alg, "unknown", 8);
-                       break;
-               }
-
-               if (max_key_len < (*key)->keylen)
-                       ret = -E2BIG;
-               else {
-                       param->u.crypt.key_len = (*key)->keylen;
-                       memcpy(param->u.crypt.key, (*key)->key,
-                              (*key)->keylen);
                }
+               if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
+                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
+                               IEEE80211_STA_AUTO_CHANNEL_SEL;
+               else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
+               else
+                       sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
+               ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+               if (ret)
+                       return ret;
+               ieee80211_sta_req_auth(dev, &sdata->u.sta);
+               return 0;
+       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+               if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
+                          ETH_ALEN) == 0)
+                       return 0;
+               return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
        }
 
-       if (sta)
-               sta_info_put(sta);
-
-       return ret;
+       return -EOPNOTSUPP;
 }
 
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-static int ieee80211_ioctl_wpa_trigger(struct net_device *dev,
-                                      struct prism2_hostapd_param *param)
+static int ieee80211_ioctl_giwap(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct sockaddr *ap_addr, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
+       struct ieee80211_sub_if_data *sdata;
 
-       if (is_broadcast_ether_addr(param->sta_addr)) {
-               local->wpa_trigger = param->u.wpa_trigger.trigger;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type == IEEE80211_IF_TYPE_STA ||
+           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               ap_addr->sa_family = ARPHRD_ETHER;
+               memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
+               return 0;
+       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+               ap_addr->sa_family = ARPHRD_ETHER;
+               memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
                return 0;
        }
 
-       sta = sta_info_get(local, param->sta_addr);
-       if (!sta) {
-               printk(KERN_DEBUG "%s: wpa_trigger - unknown addr\n",
-                      dev->name);
-               return -EINVAL;
-       }
-
-       sta->wpa_trigger = param->u.wpa_trigger.trigger;
-
-       sta_info_put(sta);
-       return 0;
+       return -EOPNOTSUPP;
 }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
 
 
-static int ieee80211_ioctl_set_rate_sets(struct net_device *dev,
-                                        struct prism2_hostapd_param *param,
-                                        int param_len)
+static int ieee80211_ioctl_siwscan(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_point *data, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u16 *pos = (u16 *) param->u.set_rate_sets.data;
-       int left = param_len - ((u8 *) pos - (u8 *) param);
-       int i, mode, num_supp, num_basic, *supp, *basic, *prev;
-       struct ieee80211_hw_mode *hw_mode;
-
-       mode = param->u.set_rate_sets.mode;
-       num_supp = param->u.set_rate_sets.num_supported_rates;
-       num_basic = param->u.set_rate_sets.num_basic_rates;
-
-       if (left < (num_supp + num_basic) * 2) {
-               printk(KERN_WARNING "%s: invalid length in hostapd set rate "
-                      "sets ioctl (%d != %d)\n", dev->name, left,
-                      (num_supp + num_basic) * 2);
-               return -EINVAL;
-       }
-
-       supp = (int *) kmalloc((num_supp + 1) * sizeof(int), GFP_KERNEL);
-       basic = (int *) kmalloc((num_basic + 1) * sizeof(int), GFP_KERNEL);
-
-       if (!supp || !basic) {
-               kfree(supp);
-               kfree(basic);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < num_supp; i++)
-               supp[i] = *pos++;
-       supp[i] = -1;
-
-       for (i = 0; i < num_basic; i++)
-               basic[i] = *pos++;
-       basic[i] = -1;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       u8 *ssid = NULL;
+       size_t ssid_len = 0;
 
-       if (num_supp == 0) {
-               kfree(supp);
-               supp = NULL;
-       }
+       if (!netif_running(dev))
+               return -ENETDOWN;
 
-       if (num_basic == 0) {
-               kfree(basic);
-               basic = NULL;
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
+               if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
+                       ssid = sdata->u.sta.ssid;
+                       ssid_len = sdata->u.sta.ssid_len;
+               }
+               break;
+       case IEEE80211_IF_TYPE_AP:
+               if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
+                       ssid = sdata->u.ap.ssid;
+                       ssid_len = sdata->u.ap.ssid_len;
+               }
+               break;
+       default:
+               return -EOPNOTSUPP;
        }
 
-       prev = local->supp_rates[mode];
-       local->supp_rates[mode] = supp;
-       kfree(prev);
-
-       prev = local->basic_rates[mode];
-       local->basic_rates[mode] = basic;
-       kfree(prev);
+       return ieee80211_sta_req_scan(dev, ssid, ssid_len);
+}
 
-       /* TODO: should update STA TX rates and remove STAs if they
-        * do not have any remaining supported rates after the change
-        */
-       list_for_each_entry(hw_mode, &local->modes_list, list)
-               if (hw_mode->mode == mode)
-                       ieee80211_prepare_rates(local, hw_mode);
 
-       return 0;
-}
-
-
-static int ieee80211_ioctl_add_if(struct net_device *dev,
-                                 struct prism2_hostapd_param *param,
-                                 int param_len)
-{
-       u8 *pos = param->u.if_info.data;
-       int left = param_len - ((u8 *) pos - (u8 *) param);
-       struct net_device *new_dev;
-       int res;
-       struct hostapd_if_wds *wds;
-       struct hostapd_if_bss *bss;
-
-       printk(KERN_WARNING "PRISM2_HOSTAPD_ADD_IF ioctl is deprecated!");
-       switch (param->u.if_info.type) {
-       case HOSTAP_IF_WDS:
-               wds = (struct hostapd_if_wds *) param->u.if_info.data;
-
-               if (left < sizeof(struct hostapd_if_wds))
-                       return -EPROTO;
-
-               res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev,
-                                      IEEE80211_IF_TYPE_WDS);
-               if (res)
-                       return res;
-               res = ieee80211_if_update_wds(new_dev, wds->remote_addr);
-               if (unlikely(res)) {
-                       struct ieee80211_local *local =
-                               wdev_priv(dev->ieee80211_ptr);
-                       struct ieee80211_sub_if_data *sdata =
-                               IEEE80211_DEV_TO_SUB_IF(new_dev);
-                       write_lock_bh(&local->sub_if_lock);
-                       list_del(&sdata->list);
-                       write_unlock_bh(&local->sub_if_lock);
-                       __ieee80211_if_del(local, sdata);
-               }
-               return res;
-       case HOSTAP_IF_VLAN:
-               if (left < sizeof(struct hostapd_if_vlan))
-                       return -EPROTO;
-
-               res = ieee80211_if_add(dev, param->u.if_info.name, NULL,
-                                      IEEE80211_IF_TYPE_VLAN);
-               return res;
-       case HOSTAP_IF_BSS:
-               bss = (struct hostapd_if_bss *) param->u.if_info.data;
-
-               if (left < sizeof(struct hostapd_if_bss))
-                       return -EPROTO;
-
-               res = ieee80211_if_add(dev, param->u.if_info.name, &new_dev,
-                                      IEEE80211_IF_TYPE_AP);
-               if (res)
-                       return res;
-               memcpy(new_dev->dev_addr, bss->bssid, ETH_ALEN);
-               return 0;
-       case HOSTAP_IF_STA:
-               if (left < sizeof(struct hostapd_if_sta))
-                       return -EPROTO;
-
-               res = ieee80211_if_add(dev, param->u.if_info.name, NULL,
-                                      IEEE80211_IF_TYPE_STA);
-               return res;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ieee80211_ioctl_remove_if(struct net_device *dev,
-                                    struct prism2_hostapd_param *param)
-{
-       unsigned int type;
-
-       switch (param->u.if_info.type) {
-       case HOSTAP_IF_WDS:
-               type = IEEE80211_IF_TYPE_WDS;
-               break;
-       case HOSTAP_IF_VLAN:
-               type = IEEE80211_IF_TYPE_VLAN;
-               break;
-       case HOSTAP_IF_BSS:
-               type = IEEE80211_IF_TYPE_AP;
-               break;
-       case HOSTAP_IF_STA:
-               type = IEEE80211_IF_TYPE_STA;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return ieee80211_if_remove(dev, param->u.if_info.name, type);
-}
-
-static int ieee80211_ioctl_update_if(struct net_device *dev,
-                                    struct prism2_hostapd_param *param,
-                                    int param_len)
-{
-       u8 *pos = param->u.if_info.data;
-       int left = param_len - ((u8 *) pos - (u8 *) param);
-
-       if (param->u.if_info.type == HOSTAP_IF_WDS) {
-               struct hostapd_if_wds *wds =
-                       (struct hostapd_if_wds *) param->u.if_info.data;
-               struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-               struct net_device *wds_dev = NULL;
-               struct ieee80211_sub_if_data *sdata;
-
-               if (left < sizeof(struct ieee80211_if_wds))
-                       return -EPROTO;
-
-               read_lock(&local->sub_if_lock);
-               list_for_each_entry(sdata, &local->sub_if_list, list) {
-                       if (strcmp(param->u.if_info.name,
-                                  sdata->dev->name) == 0) {
-                               wds_dev = sdata->dev;
-                               break;
-                       }
-               }
-               read_unlock(&local->sub_if_lock);
-
-               if (!wds_dev || sdata->type != IEEE80211_IF_TYPE_WDS)
-                       return -ENODEV;
-
-               return ieee80211_if_update_wds(wds_dev, wds->remote_addr);
-       } else {
-               return -EOPNOTSUPP;
-       }
-}
-
-
-static int ieee80211_ioctl_scan_req(struct net_device *dev,
-                                   struct prism2_hostapd_param *param,
-                                   int param_len)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u8 *pos = param->u.scan_req.ssid;
-       int left = param_len - ((u8 *) pos - (u8 *) param);
-       int len = param->u.scan_req.ssid_len;
-
-       if (local->user_space_mlme)
-               return -EOPNOTSUPP;
-
-       if (!netif_running(dev))
-               return -ENETDOWN;
-
-       if (left < len || len > IEEE80211_MAX_SSID_LEN)
-               return -EINVAL;
-
-       return ieee80211_sta_req_scan(dev, pos, len);
-}
-
-
-static int ieee80211_ioctl_sta_get_state(struct net_device *dev,
-                                        struct prism2_hostapd_param *param)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS)
-               return -EINVAL;
-       param->u.sta_get_state.state = sdata->u.sta.state;
-       return 0;
-}
-
-
-static int ieee80211_ioctl_mlme(struct net_device *dev,
-                               struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-
-       if (local->user_space_mlme)
-               return -EOPNOTSUPP;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS)
-               return -EINVAL;
-       switch (param->u.mlme.cmd) {
-       case MLME_STA_DEAUTH:
-               return ieee80211_sta_deauthenticate(dev, param->u.mlme.reason_code);
-       case MLME_STA_DISASSOC:
-               return ieee80211_sta_disassociate(dev, param->u.mlme.reason_code);
-       }
-       return 0;
-}
-
-
-static int ieee80211_ioctl_get_load_stats(struct net_device *dev,
-                                         struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       param->u.get_load_stats.channel_use = local->channel_use;
-/*     if (param->u.get_load_stats.flags & LOAD_STATS_CLEAR)
-               local->channel_use = 0; */ /* now it's not raw counter */
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_set_sta_vlan(struct net_device *dev,
-                                       struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-
-       sta = sta_info_get(local, param->sta_addr);
-       if (sta) {
-               struct net_device *new_vlan_dev;
-               new_vlan_dev =
-                       dev_get_by_name(param->u.set_sta_vlan.vlan_name);
-               if (new_vlan_dev) {
-#if 0
-                       printk("%s: Station " MAC_FMT " moved to vlan: %s\n",
-                              dev->name, MAC_ARG(param->sta_addr),
-                              new_vlan_dev->name);
-#endif
-                       if (sta->dev != new_vlan_dev) {
-                               ieee80211_send_layer2_update(new_vlan_dev,
-                                                            sta->addr);
-                       }
-                       sta->dev = new_vlan_dev;
-                       sta->vlan_id = param->u.set_sta_vlan.vlan_id;
-                       dev_put(new_vlan_dev);
-               }
-               sta_info_put(sta);
-       }
-
-       return sta ? 0 : -ENOENT;
-}
-
-
-static int ieee80211_set_gen_ie(struct net_device *dev, u8 *ie, size_t len)
-{
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       if (local->user_space_mlme)
-               return -EOPNOTSUPP;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               int ret = ieee80211_sta_set_extra_ie(dev, ie, len);
-               if (ret)
-                       return ret;
-               sdata->u.sta.auto_bssid_sel = 0;
-               ieee80211_sta_req_auth(dev, &sdata->u.sta);
-               return 0;
-       }
-
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
-               kfree(sdata->u.ap.generic_elem);
-               sdata->u.ap.generic_elem = kmalloc(len, GFP_KERNEL);
-               if (!sdata->u.ap.generic_elem)
-                       return -ENOMEM;
-               memcpy(sdata->u.ap.generic_elem, ie, len);
-               sdata->u.ap.generic_elem_len = len;
-               return ieee80211_if_config(dev);
-       }
-       return -EOPNOTSUPP;
-}
-
-
-static int
-ieee80211_ioctl_set_generic_info_elem(struct net_device *dev,
-                                     struct prism2_hostapd_param *param,
-                                     int param_len)
-{
-       u8 *pos = param->u.set_generic_info_elem.data;
-       int left = param_len - ((u8 *) pos - (u8 *) param);
-       int len = param->u.set_generic_info_elem.len;
-
-       if (left < len)
-               return -EINVAL;
-
-       return ieee80211_set_gen_ie(dev, pos, len);
-}
-
-
-static int ieee80211_ioctl_set_regulatory_domain(struct net_device *dev,
-                                           struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
-       conf->regulatory_domain = param->u.set_regulatory_domain.rd;
-       return 0;
-}
-
-
-static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev,
-                                            int val)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
-
-       conf->radio_enabled = val;
-       return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr));
-}
-
-static int
-ieee80211_ioctl_set_tx_queue_params(struct net_device *dev,
-                                   struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_queue_params qparam;
-
-       if (!local->ops->conf_tx) {
-               printk(KERN_DEBUG "%s: low-level driver does not support TX "
-                      "queue configuration\n", dev->name);
-               return -EOPNOTSUPP;
-       }
-
-       memset(&qparam, 0, sizeof(qparam));
-       qparam.aifs = param->u.tx_queue_params.aifs;
-       qparam.cw_min = param->u.tx_queue_params.cw_min;
-       qparam.cw_max = param->u.tx_queue_params.cw_max;
-       qparam.burst_time = param->u.tx_queue_params.burst_time;
-
-       return local->ops->conf_tx(local_to_hw(local),
-                                 param->u.tx_queue_params.queue,
-                                 &qparam);
-}
-
-
-static int ieee80211_ioctl_get_tx_stats(struct net_device *dev,
-                                       struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_queue_stats stats;
-       int ret, i;
-
-       if (!local->ops->get_tx_stats)
-               return -EOPNOTSUPP;
-
-       memset(&stats, 0, sizeof(stats));
-       ret = local->ops->get_tx_stats(local_to_hw(local), &stats);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < 4; i++) {
-               param->u.get_tx_stats.data[i].len = stats.data[i].len;
-               param->u.get_tx_stats.data[i].limit = stats.data[i].limit;
-               param->u.get_tx_stats.data[i].count = stats.data[i].count;
-       }
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_set_channel_flag(struct net_device *dev,
-                                           struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       struct ieee80211_channel *chan = NULL;
-       int i;
-
-       list_for_each_entry(mode, &local->modes_list, list) {
-               if (mode->mode == param->u.set_channel_flag.mode)
-                       goto found;
-       }
-       return -ENOENT;
-found:
-
-       for (i = 0; i < mode->num_channels; i++) {
-               chan = &mode->channels[i];
-               if (chan->chan == param->u.set_channel_flag.chan)
-                       break;
-               chan = NULL;
-       }
-
-       if (!chan)
-               return -ENOENT;
-
-       chan->flag = param->u.set_channel_flag.flag;
-       chan->power_level = param->u.set_channel_flag.power_level;
-       chan->antenna_max = param->u.set_channel_flag.antenna_max;
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_set_quiet_params(struct net_device *dev,
-                                           struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
-
-       conf->quiet_duration = param->u.quiet.duration;
-       conf->quiet_offset = param->u.quiet.offset;
-       conf->quiet_period = param->u.quiet.period;
-       return 0;
-}
-
-
-static int ieee80211_ioctl_set_radar_params(struct net_device *dev,
-                                           struct prism2_hostapd_param *param)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
-
-       conf->radar_firpwr_threshold = param->u.radar.radar_firpwr_threshold;
-       conf->radar_rssi_threshold = param->u.radar.radar_rssi_threshold;
-       conf->pulse_height_threshold = param->u.radar.pulse_height_threshold;
-       conf->pulse_rssi_threshold = param->u.radar.pulse_rssi_threshold;
-       conf->pulse_inband_threshold = param->u.radar.pulse_inband_threshold;
-       return 0;
-}
-
-
-static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
-                                       struct iw_point *p)
-{
-       struct prism2_hostapd_param *param;
-       int ret = 0;
-
-       if (p->length < sizeof(struct prism2_hostapd_param) ||
-           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) {
-               printk(KERN_DEBUG "%s: hostapd ioctl: ptr=%p len=%d min=%d "
-                      "max=%d\n", dev->name, p->pointer, p->length,
-                      (int)sizeof(struct prism2_hostapd_param),
-                      PRISM2_HOSTAPD_MAX_BUF_SIZE);
-               return -EINVAL;
-       }
-
-       param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
-       if (!param)
-               return -ENOMEM;
-
-       if (copy_from_user(param, p->pointer, p->length)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       switch (param->cmd) {
-       case PRISM2_HOSTAPD_FLUSH:
-               ret = ieee80211_ioctl_flush(dev, param);
-               break;
-       case PRISM2_HOSTAPD_ADD_STA:
-               ret = ieee80211_ioctl_add_sta(dev, param);
-               break;
-       case PRISM2_HOSTAPD_REMOVE_STA:
-               ret = ieee80211_ioctl_remove_sta(dev, param);
-               break;
-       case PRISM2_HOSTAPD_GET_INFO_STA:
-               ret = ieee80211_ioctl_get_info_sta(dev, param);
-               break;
-       case PRISM2_SET_ENCRYPTION:
-               ret = ieee80211_ioctl_set_encryption(dev, param, p->length);
-               break;
-       case PRISM2_GET_ENCRYPTION:
-               ret = ieee80211_ioctl_get_encryption(dev, param, p->length);
-               break;
-       case PRISM2_HOSTAPD_SET_FLAGS_STA:
-               ret = ieee80211_ioctl_set_flags_sta(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_BEACON:
-               ret = ieee80211_ioctl_set_beacon(dev, param, p->length, 0);
-               break;
-       case PRISM2_HOSTAPD_GET_HW_FEATURES:
-               ret = ieee80211_ioctl_get_hw_features(dev, param, p->length);
-               break;
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       case PRISM2_HOSTAPD_WPA_TRIGGER:
-               ret = ieee80211_ioctl_wpa_trigger(dev, param);
-               break;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-       case PRISM2_HOSTAPD_SET_RATE_SETS:
-               ret = ieee80211_ioctl_set_rate_sets(dev, param, p->length);
-               break;
-       case PRISM2_HOSTAPD_ADD_IF:
-               ret = ieee80211_ioctl_add_if(dev, param, p->length);
-               break;
-       case PRISM2_HOSTAPD_REMOVE_IF:
-               ret = ieee80211_ioctl_remove_if(dev, param);
-               break;
-       case PRISM2_HOSTAPD_GET_DOT11COUNTERSTABLE:
-               ret = ieee80211_ioctl_get_dot11counterstable(dev, param);
-               break;
-       case PRISM2_HOSTAPD_GET_LOAD_STATS:
-               ret = ieee80211_ioctl_get_load_stats(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_STA_VLAN:
-               ret = ieee80211_ioctl_set_sta_vlan(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_GENERIC_INFO_ELEM:
-               ret = ieee80211_ioctl_set_generic_info_elem(dev, param,
-                                                           p->length);
-               break;
-       case PRISM2_HOSTAPD_SET_CHANNEL_FLAG:
-               ret = ieee80211_ioctl_set_channel_flag(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN:
-               ret = ieee80211_ioctl_set_regulatory_domain(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS:
-               ret = ieee80211_ioctl_set_tx_queue_params(dev, param);
-               break;
-       case PRISM2_HOSTAPD_GET_TX_STATS:
-               ret = ieee80211_ioctl_get_tx_stats(dev, param);
-               break;
-       case PRISM2_HOSTAPD_UPDATE_IF:
-               ret = ieee80211_ioctl_update_if(dev, param, p->length);
-               break;
-       case PRISM2_HOSTAPD_SCAN_REQ:
-               ret = ieee80211_ioctl_scan_req(dev, param, p->length);
-               break;
-       case PRISM2_STA_GET_STATE:
-               ret = ieee80211_ioctl_sta_get_state(dev, param);
-               break;
-       case PRISM2_HOSTAPD_MLME:
-               ret = ieee80211_ioctl_mlme(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_RADAR_PARAMS:
-               ret = ieee80211_ioctl_set_radar_params(dev, param);
-               break;
-       case PRISM2_HOSTAPD_SET_QUIET_PARAMS:
-               ret = ieee80211_ioctl_set_quiet_params(dev, param);
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       if (copy_to_user(p->pointer, param, p->length))
-               ret = -EFAULT;
-
- out:
-       kfree(param);
-
-       return ret;
-}
-
-
-static int ieee80211_ioctl_giwname(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  char *name, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       switch (local->hw.conf.phymode) {
-       case MODE_IEEE80211A:
-               strcpy(name, "IEEE 802.11a");
-               break;
-       case MODE_IEEE80211B:
-               strcpy(name, "IEEE 802.11b");
-               break;
-       case MODE_IEEE80211G:
-               strcpy(name, "IEEE 802.11g");
-               break;
-       case MODE_ATHEROS_TURBO:
-               strcpy(name, "5GHz Turbo");
-               break;
-       default:
-               strcpy(name, "IEEE 802.11");
-               break;
-       }
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_giwrange(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *data, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct iw_range *range = (struct iw_range *) extra;
-
-       data->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 21;
-       range->retry_capa = IW_RETRY_LIMIT;
-       range->retry_flags = IW_RETRY_LIMIT;
-       range->min_retry = 0;
-       range->max_retry = 255;
-       range->min_rts = 0;
-       range->max_rts = 2347;
-       range->min_frag = 256;
-       range->max_frag = 2346;
-
-       range->encoding_size[0] = 5;
-       range->encoding_size[1] = 13;
-       range->num_encoding_sizes = 2;
-       range->max_encoding_tokens = NUM_DEFAULT_KEYS;
-
-       range->max_qual.qual = local->hw.max_signal;
-       range->max_qual.level = local->hw.max_rssi;
-       range->max_qual.noise = local->hw.max_noise;
-       range->max_qual.updated = local->wstats_flags;
-
-       range->avg_qual.qual = local->hw.max_signal/2;
-       range->avg_qual.level = 0;
-       range->avg_qual.noise = 0;
-       range->avg_qual.updated = local->wstats_flags;
-
-       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
-                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
-       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_siwmode(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  __u32 *mode, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       int type;
-
-       if (sdata->type == IEEE80211_IF_TYPE_VLAN)
-               return -EOPNOTSUPP;
-
-       switch (*mode) {
-       case IW_MODE_MASTER:
-               type = IEEE80211_IF_TYPE_AP;
-               break;
-       case IW_MODE_INFRA:
-               type = IEEE80211_IF_TYPE_STA;
-               break;
-       case IW_MODE_ADHOC:
-               type = IEEE80211_IF_TYPE_IBSS;
-               break;
-       case IW_MODE_MONITOR:
-               type = IEEE80211_IF_TYPE_MNTR;
-               break;
-       case IW_MODE_REPEAT:
-               type = IEEE80211_IF_TYPE_WDS;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (type == sdata->type)
-               return 0;
-       if (netif_running(dev))
-               return -EBUSY;
-
-       ieee80211_if_reinit(dev);
-       ieee80211_if_set_type(dev, type);
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_giwmode(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  __u32 *mode, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       switch (sdata->type) {
-       case IEEE80211_IF_TYPE_AP:
-               *mode = IW_MODE_MASTER;
-               break;
-       case IEEE80211_IF_TYPE_STA:
-               *mode = IW_MODE_INFRA;
-               break;
-       case IEEE80211_IF_TYPE_IBSS:
-               *mode = IW_MODE_ADHOC;
-               break;
-       case IEEE80211_IF_TYPE_MNTR:
-               *mode = IW_MODE_MONITOR;
-               break;
-       case IEEE80211_IF_TYPE_WDS:
-               *mode = IW_MODE_REPEAT;
-               break;
-       case IEEE80211_IF_TYPE_VLAN:
-               *mode = IW_MODE_SECOND;         /* FIXME */
-               break;
-       default:
-               *mode = IW_MODE_AUTO;
-               break;
-       }
-       return 0;
-}
-
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
-{
-       struct ieee80211_hw_mode *mode;
-       int c, set = 0;
-       int ret = -EINVAL;
-
-       list_for_each_entry(mode, &local->modes_list, list) {
-               if (!(local->enabled_modes & (1 << mode->mode)))
-                       continue;
-               for (c = 0; c < mode->num_channels; c++) {
-                       struct ieee80211_channel *chan = &mode->channels[c];
-                       if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-                           ((chan->chan == channel) || (chan->freq == freq))) {
-                               /* Use next_mode as the mode preference to
-                                * resolve non-unique channel numbers. */
-                               if (set && mode->mode != local->next_mode)
-                                       continue;
-
-                               local->oper_channel = chan;
-                               local->oper_hw_mode = mode;
-                               set++;
-                       }
-               }
-       }
-
-       if (set) {
-               if (local->sta_scanning)
-                       ret = 0;
-               else
-                       ret = ieee80211_hw_config(local);
-
-               rate_control_clear(local);
-       }
-
-       return ret;
-}
-
-static int ieee80211_ioctl_siwfreq(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_freq *freq, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_STA)
-               sdata->u.sta.auto_channel_sel = 0;
-
-       /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
-       if (freq->e == 0) {
-               if (freq->m < 0) {
-                       if (sdata->type == IEEE80211_IF_TYPE_STA)
-                               sdata->u.sta.auto_channel_sel = 1;
-                       return 0;
-               } else
-                       return ieee80211_set_channel(local, freq->m, -1);
-       } else {
-               int i, div = 1000000;
-               for (i = 0; i < freq->e; i++)
-                       div /= 10;
-               if (div > 0)
-                       return ieee80211_set_channel(local, -1, freq->m / div);
-               else
-                       return -EINVAL;
-       }
-}
-
-
-static int ieee80211_ioctl_giwfreq(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_freq *freq, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
-        * driver for the current channel with firmware-based management */
-
-       freq->m = local->hw.conf.freq;
-       freq->e = 6;
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_siwessid(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *data, char *ssid)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       size_t len = data->length;
-
-       /* iwconfig uses nul termination in SSID.. */
-       if (len > 0 && ssid[len - 1] == '\0')
-               len--;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               int ret;
-               if (local->user_space_mlme) {
-                       if (len > IEEE80211_MAX_SSID_LEN)
-                               return -EINVAL;
-                       memcpy(sdata->u.sta.ssid, ssid, len);
-                       sdata->u.sta.ssid_len = len;
-                       return 0;
-               }
-               sdata->u.sta.auto_ssid_sel = !data->flags;
-               ret = ieee80211_sta_set_ssid(dev, ssid, len);
-               if (ret)
-                       return ret;
-               ieee80211_sta_req_auth(dev, &sdata->u.sta);
-               return 0;
-       }
-
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
-               memcpy(sdata->u.ap.ssid, ssid, len);
-               memset(sdata->u.ap.ssid + len, 0,
-                      IEEE80211_MAX_SSID_LEN - len);
-               sdata->u.ap.ssid_len = len;
-               return ieee80211_if_config(dev);
-       }
-       return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_giwessid(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *data, char *ssid)
-{
-       size_t len;
-
-       struct ieee80211_sub_if_data *sdata;
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               int res = ieee80211_sta_get_ssid(dev, ssid, &len);
-               if (res == 0) {
-                       data->length = len;
-                       data->flags = 1;
-               } else
-                       data->flags = 0;
-               return res;
-       }
-
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
-               len = sdata->u.ap.ssid_len;
-               if (len > IW_ESSID_MAX_SIZE)
-                       len = IW_ESSID_MAX_SIZE;
-               memcpy(ssid, sdata->u.ap.ssid, len);
-               data->length = len;
-               data->flags = 1;
-               return 0;
-       }
-       return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_siwap(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct sockaddr *ap_addr, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               int ret;
-               if (local->user_space_mlme) {
-                       memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
-                              ETH_ALEN);
-                       return 0;
-               }
-               if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
-                       sdata->u.sta.auto_bssid_sel = 1;
-                       sdata->u.sta.auto_channel_sel = 1;
-               } else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
-                       sdata->u.sta.auto_bssid_sel = 1;
-               else
-                       sdata->u.sta.auto_bssid_sel = 0;
-               ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
-               if (ret)
-                       return ret;
-               ieee80211_sta_req_auth(dev, &sdata->u.sta);
-               return 0;
-       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
-               if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
-                          ETH_ALEN) == 0)
-                       return 0;
-               return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
-       }
-
-       return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_giwap(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct sockaddr *ap_addr, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               ap_addr->sa_family = ARPHRD_ETHER;
-               memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
-               return 0;
-       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
-               ap_addr->sa_family = ARPHRD_ETHER;
-               memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
-               return 0;
-       }
-
-       return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_siwscan(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_point *data, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       u8 *ssid = NULL;
-       size_t ssid_len = 0;
-
-       if (!netif_running(dev))
-               return -ENETDOWN;
-
-       if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
-               if (sdata->type == IEEE80211_IF_TYPE_STA ||
-                   sdata->type == IEEE80211_IF_TYPE_IBSS) {
-                       ssid = sdata->u.sta.ssid;
-                       ssid_len = sdata->u.sta.ssid_len;
-               } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
-                       ssid = sdata->u.ap.ssid;
-                       ssid_len = sdata->u.ap.ssid_len;
-               } else
-                       return -EINVAL;
-       }
-       return ieee80211_sta_req_scan(dev, ssid, ssid_len);
-}
-
-
-static int ieee80211_ioctl_giwscan(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_point *data, char *extra)
-{
-       int res;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       if (local->sta_scanning)
-               return -EAGAIN;
-       res = ieee80211_sta_scan_results(dev, extra, data->length);
-       if (res >= 0) {
-               data->length = res;
-               return 0;
-       }
-       data->length = 0;
-       return res;
-}
-
-
-static int ieee80211_ioctl_giwrate(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rate, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA)
-               sta = sta_info_get(local, sdata->u.sta.bssid);
-       else
-               return -EOPNOTSUPP;
-       if (!sta)
-               return -ENODEV;
-       if (sta->txrate < local->oper_hw_mode->num_rates)
-               rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
-       else
-               rate->value = 0;
-       sta_info_put(sta);
-       return 0;
-}
-
-static int ieee80211_ioctl_siwrts(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rts, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       if (rts->disabled)
-               local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
-       else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
-               return -EINVAL;
-       else
-               local->rts_threshold = rts->value;
-
-       /* If the wlan card performs RTS/CTS in hardware/firmware,
-        * configure it here */
-
-       if (local->ops->set_rts_threshold)
-               local->ops->set_rts_threshold(local_to_hw(local),
-                                            local->rts_threshold);
-
-       return 0;
-}
-
-static int ieee80211_ioctl_giwrts(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rts, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       rts->value = local->rts_threshold;
-       rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
-       rts->fixed = 1;
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_siwfrag(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_param *frag, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       if (frag->disabled)
-               local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
-       else if (frag->value < 256 ||
-                frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
-               return -EINVAL;
-       else {
-               /* Fragment length must be even, so strip LSB. */
-               local->fragmentation_threshold = frag->value & ~0x1;
-       }
-
-       /* If the wlan card performs fragmentation in hardware/firmware,
-        * configure it here */
-
-       if (local->ops->set_frag_threshold)
-               local->ops->set_frag_threshold(
-                       local_to_hw(local),
-                       local->fragmentation_threshold);
-
-       return 0;
-}
-
-static int ieee80211_ioctl_giwfrag(struct net_device *dev,
+static int ieee80211_ioctl_giwscan(struct net_device *dev,
                                   struct iw_request_info *info,
-                                  struct iw_param *frag, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       frag->value = local->fragmentation_threshold;
-       frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
-       frag->fixed = 1;
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_siwretry(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_param *retry, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       if (retry->disabled ||
-           (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
-               return -EINVAL;
-
-       if (retry->flags & IW_RETRY_MAX)
-               local->long_retry_limit = retry->value;
-       else if (retry->flags & IW_RETRY_MIN)
-               local->short_retry_limit = retry->value;
-       else {
-               local->long_retry_limit = retry->value;
-               local->short_retry_limit = retry->value;
-       }
-
-       if (local->ops->set_retry_limit) {
-               return local->ops->set_retry_limit(
-                       local_to_hw(local),
-                       local->short_retry_limit,
-                       local->long_retry_limit);
-       }
-
-       return 0;
-}
-
-
-static int ieee80211_ioctl_giwretry(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_param *retry, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       retry->disabled = 0;
-       if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
-               /* first return min value, iwconfig will ask max value
-                * later if needed */
-               retry->flags |= IW_RETRY_LIMIT;
-               retry->value = local->short_retry_limit;
-               if (local->long_retry_limit != local->short_retry_limit)
-                       retry->flags |= IW_RETRY_MIN;
-               return 0;
-       }
-       if (retry->flags & IW_RETRY_MAX) {
-               retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-               retry->value = local->long_retry_limit;
-       }
-
-       return 0;
-}
-
-static int ieee80211_ioctl_clear_keys(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_key_conf key;
-       int i;
-       u8 addr[ETH_ALEN];
-       struct ieee80211_key_conf *keyconf;
-       struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta;
-
-       memset(addr, 0xff, ETH_ALEN);
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
-               for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
-                       keyconf = NULL;
-                       if (sdata->keys[i] &&
-                           !sdata->keys[i]->force_sw_encrypt &&
-                           local->ops->set_key &&
-                           (keyconf = ieee80211_key_data2conf(local,
-                                                              sdata->keys[i])))
-                               local->ops->set_key(local_to_hw(local),
-                                                  DISABLE_KEY, addr,
-                                                  keyconf, 0);
-                       kfree(keyconf);
-                       ieee80211_key_free(sdata->keys[i]);
-                       sdata->keys[i] = NULL;
-               }
-               sdata->default_key = NULL;
-       }
-       read_unlock(&local->sub_if_lock);
-
-       spin_lock_bh(&local->sta_lock);
-       list_for_each_entry(sta, &local->sta_list, list) {
-               keyconf = NULL;
-               if (sta->key && !sta->key->force_sw_encrypt &&
-                   local->ops->set_key &&
-                   (keyconf = ieee80211_key_data2conf(local, sta->key)))
-                       local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-                                          sta->addr, keyconf, sta->aid);
-               kfree(keyconf);
-               ieee80211_key_free(sta->key);
-               sta->key = NULL;
-       }
-       spin_unlock_bh(&local->sta_lock);
-
-       memset(&key, 0, sizeof(key));
-       if (local->ops->set_key &&
-                   local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
-                                      NULL, &key, 0))
-               printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
-                      dev->name);
-
-       return 0;
-}
-
-
-static int
-ieee80211_ioctl_force_unicast_rate(struct net_device *dev,
-                                  struct ieee80211_sub_if_data *sdata,
-                                  int rate)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       int i;
-
-       if (sdata->type != IEEE80211_IF_TYPE_AP)
-               return -ENOENT;
-
-       if (rate == 0) {
-               sdata->u.ap.force_unicast_rateidx = -1;
-               return 0;
-       }
-
-       mode = local->oper_hw_mode;
-       for (i = 0; i < mode->num_rates; i++) {
-               if (mode->rates[i].rate == rate) {
-                       sdata->u.ap.force_unicast_rateidx = i;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-
-static int
-ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev,
-                                 struct ieee80211_sub_if_data *sdata,
-                                 int rate)
+                                  struct iw_point *data, char *extra)
 {
+       int res;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       int i;
-
-       if (sdata->type != IEEE80211_IF_TYPE_AP)
-               return -ENOENT;
-
-       if (rate == 0) {
-               sdata->u.ap.max_ratectrl_rateidx = -1;
+       if (local->sta_scanning)
+               return -EAGAIN;
+       res = ieee80211_sta_scan_results(dev, extra, data->length);
+       if (res >= 0) {
+               data->length = res;
                return 0;
        }
+       data->length = 0;
+       return res;
+}
 
-       mode = local->oper_hw_mode;
-       for (i = 0; i < mode->num_rates; i++) {
-               if (mode->rates[i].rate == rate) {
-                       sdata->u.ap.max_ratectrl_rateidx = i;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-
-static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
-                                        struct ieee80211_key *key)
-{
-       struct ieee80211_key_conf *keyconf;
-       u8 addr[ETH_ALEN];
-
-       if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt ||
-           (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
-               return;
-
-       memset(addr, 0xff, ETH_ALEN);
-       keyconf = ieee80211_key_data2conf(local, key);
-       if (keyconf && local->ops->set_key &&
-           local->ops->set_key(local_to_hw(local),
-                              SET_KEY, addr, keyconf, 0) == 0) {
-               key->force_sw_encrypt =
-                       !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
-               key->hw_key_idx = keyconf->hw_key_idx;
-       }
-       kfree(keyconf);
-}
-
-
-static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local,
-                                         struct ieee80211_key *key)
-{
-       struct ieee80211_key_conf *keyconf;
-       u8 addr[ETH_ALEN];
-
-       if (!key || key->alg != ALG_WEP || key->force_sw_encrypt ||
-           (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
-               return;
-
-       memset(addr, 0xff, ETH_ALEN);
-       keyconf = ieee80211_key_data2conf(local, key);
-       if (keyconf && local->ops->set_key)
-               local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-                                  addr, keyconf, 0);
-       kfree(keyconf);
-       key->force_sw_encrypt = 1;
-}
-
-
-static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local,
-                                           int value)
-{
-       int i;
-       struct ieee80211_sub_if_data *sdata;
-
-       local->default_wep_only = value;
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list)
-               for (i = 0; i < NUM_DEFAULT_KEYS; i++)
-                       if (value)
-                               ieee80211_key_enable_hwaccel(local,
-                                                            sdata->keys[i]);
-                       else
-                               ieee80211_key_disable_hwaccel(local,
-                                                             sdata->keys[i]);
-       read_unlock(&local->sub_if_lock);
-
-       return 0;
-}
-
-
-void ieee80211_update_default_wep_only(struct ieee80211_local *local)
-{
-       int i = 0;
-       struct ieee80211_sub_if_data *sdata;
-
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
-
-               if (sdata->dev == local->mdev)
-                       continue;
-
-               /* If there is an AP interface then depend on userspace to
-                  set default_wep_only correctly. */
-               if (sdata->type == IEEE80211_IF_TYPE_AP) {
-                       read_unlock(&local->sub_if_lock);
-                       return;
-               }
-
-               i++;
-       }
-
-       read_unlock(&local->sub_if_lock);
-
-       if (i <= 1)
-               ieee80211_ioctl_default_wep_only(local, 1);
-       else
-               ieee80211_ioctl_default_wep_only(local, 0);
-}
-
-
-static int ieee80211_ioctl_prism2_param(struct net_device *dev,
-                                       struct iw_request_info *info,
-                                       void *wrqu, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
-       int *i = (int *) extra;
-       int param = *i;
-       int value = *(i + 1);
-       int ret = 0;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (param) {
-       case PRISM2_PARAM_HOST_ENCRYPT:
-       case PRISM2_PARAM_HOST_DECRYPT:
-               /* TODO: implement these; return success now to prevent
-                * hostapd from aborting */
-               break;
-
-       case PRISM2_PARAM_BEACON_INT:
-               local->hw.conf.beacon_int = value;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-               local->bridge_packets = value;
-               break;
-
-       case PRISM2_PARAM_AP_AUTH_ALGS:
-               if (sdata->type == IEEE80211_IF_TYPE_STA ||
-                   sdata->type == IEEE80211_IF_TYPE_IBSS) {
-                       sdata->u.sta.auth_algs = value;
-               } else
-                       ret = -EOPNOTSUPP;
-               break;
-
-       case PRISM2_PARAM_DTIM_PERIOD:
-               if (value < 1)
-                       ret = -EINVAL;
-               else if (sdata->type != IEEE80211_IF_TYPE_AP)
-                       ret = -ENOENT;
-               else
-                       sdata->u.ap.dtim_period = value;
-               break;
-
-       case PRISM2_PARAM_IEEE_802_1X:
-               if (local->ops->set_ieee8021x)
-                       ret = local->ops->set_ieee8021x(local_to_hw(local),
-                                                       value);
-               if (ret)
-                       printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
-                              "for low-level driver\n", dev->name, value);
-               else
-                       sdata->ieee802_1x = value;
-               break;
-
-       case PRISM2_PARAM_ANTSEL_TX:
-               local->hw.conf.antenna_sel_tx = value;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_ANTSEL_RX:
-               local->hw.conf.antenna_sel_rx = value;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
-               local->cts_protect_erp_frames = value;
-               break;
-
-       case PRISM2_PARAM_DROP_UNENCRYPTED:
-               sdata->drop_unencrypted = value;
-               break;
-
-       case PRISM2_PARAM_PREAMBLE:
-               local->short_preamble = value;
-               break;
-
-       case PRISM2_PARAM_STAT_TIME:
-               if (!local->stat_time && value) {
-                       local->stat_timer.expires = jiffies + HZ * value / 100;
-                       add_timer(&local->stat_timer);
-               } else if (local->stat_time && !value) {
-                       del_timer_sync(&local->stat_timer);
-               }
-               local->stat_time = value;
-               break;
-       case PRISM2_PARAM_SHORT_SLOT_TIME:
-               if (value)
-                       local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
-               else
-                       local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_PRIVACY_INVOKED:
-               if (local->ops->set_privacy_invoked)
-                       ret = local->ops->set_privacy_invoked(
-                                       local_to_hw(local), value);
-               break;
-
-       case PRISM2_PARAM_NEXT_MODE:
-               local->next_mode = value;
-               break;
-
-       case PRISM2_PARAM_CLEAR_KEYS:
-               ret = ieee80211_ioctl_clear_keys(dev);
-               break;
-
-       case PRISM2_PARAM_RADIO_ENABLED:
-               ret = ieee80211_ioctl_set_radio_enabled(dev, value);
-               break;
-
-       case PRISM2_PARAM_ANTENNA_MODE:
-               local->hw.conf.antenna_mode = value;
-               if (ieee80211_hw_config(local))
-                       ret = -EINVAL;
-               break;
-
-       case PRISM2_PARAM_BROADCAST_SSID:
-               if ((value < 0) || (value > 1))
-                       ret = -EINVAL;
-               else if (value)
-                       local->hw.conf.flags |= IEEE80211_CONF_SSID_HIDDEN;
-               else
-                       local->hw.conf.flags &= ~IEEE80211_CONF_SSID_HIDDEN;
-               break;
-
-       case PRISM2_PARAM_STA_ANTENNA_SEL:
-               local->sta_antenna_sel = value;
-               break;
-
-       case PRISM2_PARAM_FORCE_UNICAST_RATE:
-               ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value);
-               break;
-
-       case PRISM2_PARAM_MAX_RATECTRL_RATE:
-               ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value);
-               break;
-
-       case PRISM2_PARAM_RATE_CTRL_NUM_UP:
-               local->rate_ctrl_num_up = value;
-               break;
-
-       case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
-               local->rate_ctrl_num_down = value;
-               break;
-
-       case PRISM2_PARAM_TX_POWER_REDUCTION:
-               if (value < 0)
-                       ret = -EINVAL;
-               else
-                       local->hw.conf.tx_power_reduction = value;
-               break;
-
-       case PRISM2_PARAM_EAPOL:
-               sdata->eapol = value;
-               break;
-
-       case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
-               local->key_tx_rx_threshold = value;
-               break;
-
-       case PRISM2_PARAM_KEY_INDEX:
-               if (value < 0 || value >= NUM_DEFAULT_KEYS)
-                       ret = -EINVAL;
-               else if (!sdata->keys[value])
-                       ret = -ENOENT;
-               else
-                       sdata->default_key = sdata->keys[value];
-               break;
-
-       case PRISM2_PARAM_DEFAULT_WEP_ONLY:
-               ret = ieee80211_ioctl_default_wep_only(local, value);
-               break;
-
-       case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
-               local->wifi_wme_noack_test = value;
-               break;
-
-       case PRISM2_PARAM_ALLOW_BROADCAST_ALWAYS:
-               local->allow_broadcast_always = value;
-               break;
-
-       case PRISM2_PARAM_SCAN_FLAGS:
-               local->scan_flags = value;
-               break;
-
-       case PRISM2_PARAM_MIXED_CELL:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       sdata->u.sta.mixed_cell = !!value;
-               break;
-
-       case PRISM2_PARAM_KEY_MGMT:
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
-                       ret = -EINVAL;
-               else
-                       sdata->u.sta.key_mgmt = value;
-               break;
-
-       case PRISM2_PARAM_HW_MODES:
-               local->enabled_modes = value;
-               break;
 
-       case PRISM2_PARAM_CREATE_IBSS:
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       sdata->u.sta.create_ibss = !!value;
-               break;
-       case PRISM2_PARAM_WMM_ENABLED:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       sdata->u.sta.wmm_enabled = !!value;
-               break;
-       case PRISM2_PARAM_RADAR_DETECT:
-               local->hw.conf.radar_detect = value;
-               break;
-       case PRISM2_PARAM_SPECTRUM_MGMT:
-               local->hw.conf.spect_mgmt = value;
-               break;
-       case PRISM2_PARAM_MGMT_IF:
-               if (value == 1) {
-                       if (!local->apdev)
-                               ret = ieee80211_if_add_mgmt(local);
-               } else if (value == 0) {
-                       if (local->apdev)
-                               ieee80211_if_del_mgmt(local);
-               } else
-                       ret = -EINVAL;
-               break;
-       case PRISM2_PARAM_USER_SPACE_MLME:
-               local->user_space_mlme = value;
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
+static int ieee80211_ioctl_siwrate(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rate, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hw_mode *mode;
+       int i;
+       u32 target_rate = rate->value / 100000;
+       struct ieee80211_sub_if_data *sdata;
 
-       return ret;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (!sdata->bss)
+               return -ENODEV;
+       mode = local->oper_hw_mode;
+       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+        * target_rate = X, rate->fixed = 1 means only rate X
+        * target_rate = X, rate->fixed = 0 means all rates <= X */
+       sdata->bss->max_ratectrl_rateidx = -1;
+       sdata->bss->force_unicast_rateidx = -1;
+       if (rate->value < 0)
+               return 0;
+       for (i=0; i< mode->num_rates; i++) {
+               struct ieee80211_rate *rates = &mode->rates[i];
+               int this_rate = rates->rate;
+
+               if (target_rate == this_rate) {
+                       sdata->bss->max_ratectrl_rateidx = i;
+                       if (rate->fixed)
+                               sdata->bss->force_unicast_rateidx = i;
+                       break;
+               }
+       }
+       return 0;
 }
 
-
-static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
-                                           struct iw_request_info *info,
-                                           void *wrqu, char *extra)
+static int ieee80211_ioctl_giwrate(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rate, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
-       int *param = (int *) extra;
-       int ret = 0;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->type == IEEE80211_IF_TYPE_STA)
+               sta = sta_info_get(local, sdata->u.sta.bssid);
+       else
+               return -EOPNOTSUPP;
+       if (!sta)
+               return -ENODEV;
+       if (sta->txrate < local->oper_hw_mode->num_rates)
+               rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
+       else
+               rate->value = 0;
+       sta_info_put(sta);
+       return 0;
+}
 
-       switch (*param) {
-       case PRISM2_PARAM_BEACON_INT:
-               *param = local->hw.conf.beacon_int;
-               break;
+static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
+                                     struct iw_request_info *info,
+                                     union iwreq_data *data, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       bool need_reconfig = 0;
 
-       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-               *param = local->bridge_packets;
-               break;
+       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+               return -EINVAL;
+       if (data->txpower.flags & IW_TXPOW_RANGE)
+               return -EINVAL;
+       if (!data->txpower.fixed)
+               return -EINVAL;
 
-       case PRISM2_PARAM_AP_AUTH_ALGS:
-               if (sdata->type == IEEE80211_IF_TYPE_STA ||
-                   sdata->type == IEEE80211_IF_TYPE_IBSS) {
-                       *param = sdata->u.sta.auth_algs;
-               } else
-                       ret = -EOPNOTSUPP;
-               break;
+       if (local->hw.conf.power_level != data->txpower.value) {
+               local->hw.conf.power_level = data->txpower.value;
+               need_reconfig = 1;
+       }
+       if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
+               local->hw.conf.radio_enabled = !(data->txpower.disabled);
+               need_reconfig = 1;
+       }
+       if (need_reconfig) {
+               ieee80211_hw_config(local);
+               /* The return value of hw_config is not of big interest here,
+                * as it doesn't say that it failed because of _this_ config
+                * change or something else. Ignore it. */
+       }
 
-       case PRISM2_PARAM_DTIM_PERIOD:
-               if (sdata->type != IEEE80211_IF_TYPE_AP)
-                       ret = -ENOENT;
-               else
-                       *param = sdata->u.ap.dtim_period;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_IEEE_802_1X:
-               *param = sdata->ieee802_1x;
-               break;
+static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *data, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_ANTSEL_TX:
-               *param = local->hw.conf.antenna_sel_tx;
-               break;
+       data->txpower.fixed = 1;
+       data->txpower.disabled = !(local->hw.conf.radio_enabled);
+       data->txpower.value = local->hw.conf.power_level;
+       data->txpower.flags = IW_TXPOW_DBM;
 
-       case PRISM2_PARAM_ANTSEL_RX:
-               *param = local->hw.conf.antenna_sel_rx;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
-               *param = local->cts_protect_erp_frames;
-               break;
+static int ieee80211_ioctl_siwrts(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rts, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_DROP_UNENCRYPTED:
-               *param = sdata->drop_unencrypted;
-               break;
+       if (rts->disabled)
+               local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+       else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
+               return -EINVAL;
+       else
+               local->rts_threshold = rts->value;
 
-       case PRISM2_PARAM_PREAMBLE:
-               *param = local->short_preamble;
-               break;
+       /* If the wlan card performs RTS/CTS in hardware/firmware,
+        * configure it here */
 
-       case PRISM2_PARAM_STAT_TIME:
-               *param = local->stat_time;
-               break;
-       case PRISM2_PARAM_SHORT_SLOT_TIME:
-               *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
-               break;
+       if (local->ops->set_rts_threshold)
+               local->ops->set_rts_threshold(local_to_hw(local),
+                                            local->rts_threshold);
 
-       case PRISM2_PARAM_NEXT_MODE:
-               *param = local->next_mode;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_ANTENNA_MODE:
-               *param = local->hw.conf.antenna_mode;
-               break;
+static int ieee80211_ioctl_giwrts(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rts, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_BROADCAST_SSID:
-               *param = !!(local->hw.conf.flags & IEEE80211_CONF_SSID_HIDDEN);
-               break;
+       rts->value = local->rts_threshold;
+       rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
+       rts->fixed = 1;
 
-       case PRISM2_PARAM_STA_ANTENNA_SEL:
-               *param = local->sta_antenna_sel;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_RATE_CTRL_NUM_UP:
-               *param = local->rate_ctrl_num_up;
-               break;
 
-       case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
-               *param = local->rate_ctrl_num_down;
-               break;
+static int ieee80211_ioctl_siwfrag(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_param *frag, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_TX_POWER_REDUCTION:
-               *param = local->hw.conf.tx_power_reduction;
-               break;
+       if (frag->disabled)
+               local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+       else if (frag->value < 256 ||
+                frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
+               return -EINVAL;
+       else {
+               /* Fragment length must be even, so strip LSB. */
+               local->fragmentation_threshold = frag->value & ~0x1;
+       }
 
-       case PRISM2_PARAM_EAPOL:
-               *param = sdata->eapol;
-               break;
+       /* If the wlan card performs fragmentation in hardware/firmware,
+        * configure it here */
 
-       case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
-               *param = local->key_tx_rx_threshold;
-               break;
+       if (local->ops->set_frag_threshold)
+               local->ops->set_frag_threshold(
+                       local_to_hw(local),
+                       local->fragmentation_threshold);
 
-       case PRISM2_PARAM_KEY_INDEX:
-               if (!sdata->default_key)
-                       ret = -ENOENT;
-               else if (sdata->default_key == sdata->keys[0])
-                       *param = 0;
-               else if (sdata->default_key == sdata->keys[1])
-                       *param = 1;
-               else if (sdata->default_key == sdata->keys[2])
-                       *param = 2;
-               else if (sdata->default_key == sdata->keys[3])
-                       *param = 3;
-               else
-                       ret = -ENOENT;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_DEFAULT_WEP_ONLY:
-               *param = local->default_wep_only;
-               break;
+static int ieee80211_ioctl_giwfrag(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  struct iw_param *frag, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
-               *param = local->wifi_wme_noack_test;
-               break;
+       frag->value = local->fragmentation_threshold;
+       frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
+       frag->fixed = 1;
 
-       case PRISM2_PARAM_ALLOW_BROADCAST_ALWAYS:
-               *param = local->allow_broadcast_always;
-               break;
+       return 0;
+}
 
-       case PRISM2_PARAM_SCAN_FLAGS:
-               *param = local->scan_flags;
-               break;
 
-       case PRISM2_PARAM_HW_MODES:
-               *param = local->enabled_modes;
-               break;
+static int ieee80211_ioctl_siwretry(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_param *retry, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       case PRISM2_PARAM_CREATE_IBSS:
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!sdata->u.sta.create_ibss;
-               break;
+       if (retry->disabled ||
+           (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+               return -EINVAL;
 
-       case PRISM2_PARAM_MIXED_CELL:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!sdata->u.sta.mixed_cell;
-               break;
+       if (retry->flags & IW_RETRY_MAX)
+               local->long_retry_limit = retry->value;
+       else if (retry->flags & IW_RETRY_MIN)
+               local->short_retry_limit = retry->value;
+       else {
+               local->long_retry_limit = retry->value;
+               local->short_retry_limit = retry->value;
+       }
 
-       case PRISM2_PARAM_KEY_MGMT:
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
-                       ret = -EINVAL;
-               else
-                       *param = sdata->u.sta.key_mgmt;
-               break;
-       case PRISM2_PARAM_WMM_ENABLED:
-               if (sdata->type != IEEE80211_IF_TYPE_STA &&
-                   sdata->type != IEEE80211_IF_TYPE_IBSS)
-                       ret = -EINVAL;
-               else
-                       *param = !!sdata->u.sta.wmm_enabled;
-               break;
-       case PRISM2_PARAM_MGMT_IF:
-               if (local->apdev)
-                       *param = local->apdev->ifindex;
-               else
-                       ret = -ENOENT;
-               break;
-       case PRISM2_PARAM_USER_SPACE_MLME:
-               *param = local->user_space_mlme;
-               break;
+       if (local->ops->set_retry_limit) {
+               return local->ops->set_retry_limit(
+                       local_to_hw(local),
+                       local->short_retry_limit,
+                       local->long_retry_limit);
+       }
 
-       default:
-               ret = -EOPNOTSUPP;
-               break;
+       return 0;
+}
+
+
+static int ieee80211_ioctl_giwretry(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_param *retry, char *extra)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+       retry->disabled = 0;
+       if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
+               /* first return min value, iwconfig will ask max value
+                * later if needed */
+               retry->flags |= IW_RETRY_LIMIT;
+               retry->value = local->short_retry_limit;
+               if (local->long_retry_limit != local->short_retry_limit)
+                       retry->flags |= IW_RETRY_MIN;
+               return 0;
+       }
+       if (retry->flags & IW_RETRY_MAX) {
+               retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+               retry->value = local->long_retry_limit;
        }
 
-       return ret;
+       return 0;
 }
 
 static int ieee80211_ioctl_siwmlme(struct net_device *dev,
@@ -2713,6 +825,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
        int idx, i, alg = ALG_WEP;
        u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+       int remove = 0;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -2731,23 +844,18 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
                idx--;
 
        if (erq->flags & IW_ENCODE_DISABLED)
-               alg = ALG_NONE;
+               remove = 1;
        else if (erq->length == 0) {
                /* No key data - just set the default TX key index */
-               if (sdata->default_key != sdata->keys[idx]) {
-                       ieee80211_debugfs_key_remove_default(sdata);
-                       sdata->default_key = sdata->keys[idx];
-                       if (sdata->default_key)
-                               ieee80211_debugfs_key_add_default(sdata);
-               }
+               ieee80211_set_default_key(sdata, idx);
                return 0;
        }
 
        return ieee80211_set_encryption(
                dev, bcaddr,
-               idx, alg,
+               idx, alg, remove,
                !sdata->default_key,
-               NULL, keybuf, erq->length);
+               keybuf, erq->length);
 }
 
 
@@ -2784,23 +892,14 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
                return 0;
        }
 
-       memcpy(key, sdata->keys[idx]->key,
-              min((int)erq->length, sdata->keys[idx]->keylen));
-       erq->length = sdata->keys[idx]->keylen;
+       memcpy(key, sdata->keys[idx]->conf.key,
+              min_t(int, erq->length, sdata->keys[idx]->conf.keylen));
+       erq->length = sdata->keys[idx]->conf.keylen;
        erq->flags |= IW_ENCODE_ENABLED;
 
        return 0;
 }
 
-
-static int ieee80211_ioctl_siwgenie(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *data, char *extra)
-{
-       return ieee80211_set_gen_ie(dev, extra, data->length);
-}
-
-
 static int ieee80211_ioctl_siwauth(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_param *data, char *extra)
@@ -2821,22 +920,12 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                        ret = -EINVAL;
                else {
                        /*
-                        * TODO: sdata->u.sta.key_mgmt does not match with WE18
-                        * value completely; could consider modifying this to
-                        * be closer to WE18. For now, this value is not really
-                        * used for anything else than Privacy matching, so the
-                        * current code here should be more or less OK.
+                        * Key management was set by wpa_supplicant,
+                        * we only need this to associate to a network
+                        * that has privacy enabled regardless of not
+                        * having a key.
                         */
-                       if (data->value & IW_AUTH_KEY_MGMT_802_1X) {
-                               sdata->u.sta.key_mgmt =
-                                       IEEE80211_KEY_MGMT_WPA_EAP;
-                       } else if (data->value & IW_AUTH_KEY_MGMT_PSK) {
-                               sdata->u.sta.key_mgmt =
-                                       IEEE80211_KEY_MGMT_WPA_PSK;
-                       } else {
-                               sdata->u.sta.key_mgmt =
-                                       IEEE80211_KEY_MGMT_NONE;
-                       }
+                       sdata->u.sta.key_management_enabled = !!data->value;
                }
                break;
        case IW_AUTH_80211_AUTH_ALG:
@@ -2915,11 +1004,11 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
-       int alg, idx, i;
+       int uninitialized_var(alg), idx, i, remove = 0;
 
        switch (ext->alg) {
        case IW_ENCODE_ALG_NONE:
-               alg = ALG_NONE;
+               remove = 1;
                break;
        case IW_ENCODE_ALG_WEP:
                alg = ALG_WEP;
@@ -2935,7 +1024,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
        }
 
        if (erq->flags & IW_ENCODE_DISABLED)
-               alg = ALG_NONE;
+               remove = 1;
 
        idx = erq->flags & IW_ENCODE_INDEX;
        if (idx < 1 || idx > 4) {
@@ -2954,39 +1043,10 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
                idx--;
 
        return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+                                       remove,
                                        ext->ext_flags &
                                        IW_ENCODE_EXT_SET_TX_KEY,
-                                       NULL, ext->key, ext->key_len);
-}
-
-
-static const struct iw_priv_args ieee80211_ioctl_priv[] = {
-       { PRISM2_IOCTL_PRISM2_PARAM,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
-       { PRISM2_IOCTL_GET_PRISM2_PARAM,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
-};
-
-
-int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct iwreq *wrq = (struct iwreq *) rq;
-       int ret = 0;
-
-       switch (cmd) {
-               /* Private ioctls (iwpriv) that have not yet been converted
-                * into new wireless extensions API */
-       case PRISM2_IOCTL_HOSTAPD:
-               if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
-               else ret = ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data);
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       return ret;
+                                       ext->key, ext->key_len);
 }
 
 
@@ -3010,10 +1070,10 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) NULL /* kernel code */,            /* SIOCGIWPRIV */
        (iw_handler) NULL /* not used */,               /* SIOCSIWSTATS */
        (iw_handler) NULL /* kernel code */,            /* SIOCGIWSTATS */
-       iw_handler_set_spy,                             /* SIOCSIWSPY */
-       iw_handler_get_spy,                             /* SIOCGIWSPY */
-       iw_handler_set_thrspy,                          /* SIOCSIWTHRSPY */
-       iw_handler_get_thrspy,                          /* SIOCGIWTHRSPY */
+       (iw_handler) NULL,                              /* SIOCSIWSPY */
+       (iw_handler) NULL,                              /* SIOCGIWSPY */
+       (iw_handler) NULL,                              /* SIOCSIWTHRSPY */
+       (iw_handler) NULL,                              /* SIOCGIWTHRSPY */
        (iw_handler) ieee80211_ioctl_siwap,             /* SIOCSIWAP */
        (iw_handler) ieee80211_ioctl_giwap,             /* SIOCGIWAP */
        (iw_handler) ieee80211_ioctl_siwmlme,           /* SIOCSIWMLME */
@@ -3026,14 +1086,14 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) NULL,                              /* SIOCGIWNICKN */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
-       (iw_handler) NULL,                              /* SIOCSIWRATE */
+       (iw_handler) ieee80211_ioctl_siwrate,           /* SIOCSIWRATE */
        (iw_handler) ieee80211_ioctl_giwrate,           /* SIOCGIWRATE */
        (iw_handler) ieee80211_ioctl_siwrts,            /* SIOCSIWRTS */
        (iw_handler) ieee80211_ioctl_giwrts,            /* SIOCGIWRTS */
        (iw_handler) ieee80211_ioctl_siwfrag,           /* SIOCSIWFRAG */
        (iw_handler) ieee80211_ioctl_giwfrag,           /* SIOCGIWFRAG */
-       (iw_handler) NULL,                              /* SIOCSIWTXPOW */
-       (iw_handler) NULL,                              /* SIOCGIWTXPOW */
+       (iw_handler) ieee80211_ioctl_siwtxpower,        /* SIOCSIWTXPOW */
+       (iw_handler) ieee80211_ioctl_giwtxpower,        /* SIOCGIWTXPOW */
        (iw_handler) ieee80211_ioctl_siwretry,          /* SIOCSIWRETRY */
        (iw_handler) ieee80211_ioctl_giwretry,          /* SIOCGIWRETRY */
        (iw_handler) ieee80211_ioctl_siwencode,         /* SIOCSIWENCODE */
@@ -3052,19 +1112,9 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) NULL,                              /* -- hole -- */
 };
 
-static const iw_handler ieee80211_private_handler[] =
-{                                                      /* SIOCIWFIRSTPRIV + */
-       (iw_handler) ieee80211_ioctl_prism2_param,      /* 0 */
-       (iw_handler) ieee80211_ioctl_get_prism2_param,  /* 1 */
-};
-
 const struct iw_handler_def ieee80211_iw_handler_def =
 {
        .num_standard   = ARRAY_SIZE(ieee80211_handler),
-       .num_private    = ARRAY_SIZE(ieee80211_private_handler),
-       .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
        .standard       = (iw_handler *) ieee80211_handler,
-       .private        = (iw_handler *) ieee80211_private_handler,
-       .private_args   = (struct iw_priv_args *) ieee80211_ioctl_priv,
        .get_wireless_stats = ieee80211_get_wireless_stats,
 };
index c33384912782f0c71395bc80fae8664ee67ac7f2..fc770e98d47b44f3ba64250600db08823714c423 100644 (file)
@@ -11,7 +11,7 @@
 #define IEEE80211_KEY_H
 
 #include <linux/types.h>
-#include <linux/kref.h>
+#include <linux/list.h>
 #include <linux/crypto.h>
 #include <net/mac80211.h>
 
 
 #define NUM_RX_DATA_QUEUES 17
 
+struct ieee80211_local;
+struct ieee80211_sub_if_data;
+struct sta_info;
+
+#define KEY_FLAG_UPLOADED_TO_HARDWARE  (1<<0)
+
 struct ieee80211_key {
-       struct kref kref;
+       struct ieee80211_local *local;
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
+
+       struct list_head list;
+
+       unsigned int flags;
 
-       int hw_key_idx; /* filled and used by low-level driver */
-       ieee80211_key_alg alg;
        union {
                struct {
                        /* last used TSC */
@@ -73,22 +83,16 @@ struct ieee80211_key {
                        u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
                } ccmp;
        } u;
-       int tx_rx_count; /* number of times this key has been used */
-       int keylen;
 
-       /* if the low level driver can provide hardware acceleration it should
-        * clear this flag */
-       unsigned int force_sw_encrypt:1;
-       unsigned int default_tx_key:1; /* This key is the new default TX key
-                                       * (used only for broadcast keys). */
-       s8 keyidx; /* WEP key index */
+       /* number of times this key has been used */
+       int tx_rx_count;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct {
                struct dentry *stalink;
                struct dentry *dir;
                struct dentry *keylen;
-               struct dentry *force_sw_encrypt;
+               struct dentry *flags;
                struct dentry *keyidx;
                struct dentry *hw_key_idx;
                struct dentry *tx_rx_count;
@@ -97,10 +101,27 @@ struct ieee80211_key {
                struct dentry *rx_spec;
                struct dentry *replays;
                struct dentry *key;
+               struct dentry *ifindex;
        } debugfs;
 #endif
 
-       u8 key[0];
+       /*
+        * key config, must be last because it contains key
+        * material as variable length member
+        */
+       struct ieee80211_key_conf conf;
 };
 
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+                                         struct sta_info *sta,
+                                         enum ieee80211_key_alg alg,
+                                         int idx,
+                                         size_t key_len,
+                                         const u8 *key_data);
+void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
+
 #endif /* IEEE80211_KEY_H */
index 719d75b207073f1224322f7e14b3083b9346c323..4cf89af9d1009ffc528622d2e0f64a550c4614d4 100644 (file)
@@ -33,33 +33,58 @@ void ieee80211_led_tx(struct ieee80211_local *local, int q)
                led_trigger_event(local->tx_led, LED_FULL);
 }
 
+void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
+{
+       if (unlikely(!local->assoc_led))
+               return;
+       if (associated)
+               led_trigger_event(local->assoc_led, LED_FULL);
+       else
+               led_trigger_event(local->assoc_led, LED_OFF);
+}
+
 void ieee80211_led_init(struct ieee80211_local *local)
 {
        local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (!local->rx_led)
-               return;
-       snprintf(local->rx_led_name, sizeof(local->rx_led_name),
-                "%srx", wiphy_name(local->hw.wiphy));
-       local->rx_led->name = local->rx_led_name;
-       if (led_trigger_register(local->rx_led)) {
-               kfree(local->rx_led);
-               local->rx_led = NULL;
+       if (local->rx_led) {
+               snprintf(local->rx_led_name, sizeof(local->rx_led_name),
+                        "%srx", wiphy_name(local->hw.wiphy));
+               local->rx_led->name = local->rx_led_name;
+               if (led_trigger_register(local->rx_led)) {
+                       kfree(local->rx_led);
+                       local->rx_led = NULL;
+               }
        }
 
        local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (!local->tx_led)
-               return;
-       snprintf(local->tx_led_name, sizeof(local->tx_led_name),
-                "%stx", wiphy_name(local->hw.wiphy));
-       local->tx_led->name = local->tx_led_name;
-       if (led_trigger_register(local->tx_led)) {
-               kfree(local->tx_led);
-               local->tx_led = NULL;
+       if (local->tx_led) {
+               snprintf(local->tx_led_name, sizeof(local->tx_led_name),
+                        "%stx", wiphy_name(local->hw.wiphy));
+               local->tx_led->name = local->tx_led_name;
+               if (led_trigger_register(local->tx_led)) {
+                       kfree(local->tx_led);
+                       local->tx_led = NULL;
+               }
+       }
+
+       local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+       if (local->assoc_led) {
+               snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
+                        "%sassoc", wiphy_name(local->hw.wiphy));
+               local->assoc_led->name = local->assoc_led_name;
+               if (led_trigger_register(local->assoc_led)) {
+                       kfree(local->assoc_led);
+                       local->assoc_led = NULL;
+               }
        }
 }
 
 void ieee80211_led_exit(struct ieee80211_local *local)
 {
+       if (local->assoc_led) {
+               led_trigger_unregister(local->assoc_led);
+               kfree(local->assoc_led);
+       }
        if (local->tx_led) {
                led_trigger_unregister(local->tx_led);
                kfree(local->tx_led);
@@ -70,6 +95,16 @@ void ieee80211_led_exit(struct ieee80211_local *local)
        }
 }
 
+char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (local->assoc_led)
+               return local->assoc_led_name;
+       return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
+
 char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
index 5c8ab8263878f80a08fe830a4e5c4cbe174aaac9..0feb22619835e0230df6e8bf9469d76e0e49f914 100644 (file)
@@ -14,6 +14,8 @@
 #ifdef CONFIG_MAC80211_LEDS
 extern void ieee80211_led_rx(struct ieee80211_local *local);
 extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
+extern void ieee80211_led_assoc(struct ieee80211_local *local,
+                               bool associated);
 extern void ieee80211_led_init(struct ieee80211_local *local);
 extern void ieee80211_led_exit(struct ieee80211_local *local);
 #else
@@ -23,6 +25,10 @@ static inline void ieee80211_led_rx(struct ieee80211_local *local)
 static inline void ieee80211_led_tx(struct ieee80211_local *local, int q)
 {
 }
+static inline void ieee80211_led_assoc(struct ieee80211_local *local,
+                                      bool associated)
+{
+}
 static inline void ieee80211_led_init(struct ieee80211_local *local)
 {
 }
index 16e850864b8a97184497c3bd830325ea6f5b179d..93abb8fff1410f254c9fb6adf04ad34823bc80a5 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/rtnetlink.h>
 #include "ieee80211_rate.h"
 #include "ieee80211_i.h"
 
@@ -24,11 +25,10 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops)
 {
        struct rate_control_alg *alg;
 
-       alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+       alg = kzalloc(sizeof(*alg), GFP_KERNEL);
        if (alg == NULL) {
                return -ENOMEM;
        }
-       memset(alg, 0, sizeof(*alg));
        alg->ops = ops;
 
        mutex_lock(&rate_ctrl_mutex);
@@ -138,3 +138,43 @@ void rate_control_put(struct rate_control_ref *ref)
 {
        kref_put(&ref->kref, rate_control_release);
 }
+
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+                                const char *name)
+{
+       struct rate_control_ref *ref, *old;
+
+       ASSERT_RTNL();
+       if (local->open_count || netif_running(local->mdev))
+               return -EBUSY;
+
+       ref = rate_control_alloc(name, local);
+       if (!ref) {
+               printk(KERN_WARNING "%s: Failed to select rate control "
+                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               return -ENOENT;
+       }
+
+       old = local->rate_ctrl;
+       local->rate_ctrl = ref;
+       if (old) {
+               rate_control_put(old);
+               sta_info_flush(local, NULL);
+       }
+
+       printk(KERN_DEBUG "%s: Selected rate control "
+              "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
+              ref->ops->name);
+
+
+       return 0;
+}
+
+void rate_control_deinitialize(struct ieee80211_local *local)
+{
+       struct rate_control_ref *ref;
+
+       ref = local->rate_ctrl;
+       local->rate_ctrl = NULL;
+       rate_control_put(ref);
+}
index f021a028d9d0fa551b55d1b999dccdf0bcdb2be4..7cd1ebab4f8345f4cdf008b17ecc134254c45c39 100644 (file)
@@ -30,8 +30,6 @@ struct rate_control_extra {
 
        /* parameters from the caller to rate_control_get_rate(): */
        struct ieee80211_hw_mode *mode;
-       int mgmt_data; /* this is data frame that is used for management
-                       * (e.g., IEEE 802.1X EAPOL) */
        u16 ethertype;
 };
 
@@ -141,4 +139,10 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 #endif
 }
 
+
+/* functions for rate control related to a device */
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+                                const char *name);
+void rate_control_deinitialize(struct ieee80211_local *local);
+
 #endif /* IEEE80211_RATE_H */
index 0e4501db748157499cf1d89fa23146d30811466c..7c93f29c8bd46ba97f1777e1c954574069fd4993 100644 (file)
 #include <linux/wireless.h>
 #include <linux/random.h>
 #include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
-#include "hostapd_ioctl.h"
+#include "ieee80211_led.h"
 
 #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
 #define IEEE80211_AUTH_MAX_TRIES 3
@@ -59,9 +58,6 @@
 
 #define ERP_INFO_USE_PROTECTION BIT(1)
 
-/* mgmt header + 1 byte action code */
-#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
-
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                                     u8 *ssid, size_t ssid_len);
 static struct ieee80211_sta_bss *
@@ -79,47 +75,43 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 
 /* Parsed Information Elements */
 struct ieee802_11_elems {
+       /* pointers to IEs */
        u8 *ssid;
-       u8 ssid_len;
        u8 *supp_rates;
-       u8 supp_rates_len;
        u8 *fh_params;
-       u8 fh_params_len;
        u8 *ds_params;
-       u8 ds_params_len;
        u8 *cf_params;
-       u8 cf_params_len;
        u8 *tim;
-       u8 tim_len;
        u8 *ibss_params;
-       u8 ibss_params_len;
        u8 *challenge;
-       u8 challenge_len;
        u8 *wpa;
-       u8 wpa_len;
        u8 *rsn;
-       u8 rsn_len;
        u8 *erp_info;
-       u8 erp_info_len;
-       u8 *ht_cap_param;
-       u8 ht_cap_param_len;
-       u8 *ht_extra_param;
-       u8 ht_extra_param_len;
        u8 *ext_supp_rates;
-       u8 ext_supp_rates_len;
        u8 *wmm_info;
-       u8 wmm_info_len;
        u8 *wmm_param;
+
+       /* length of them, respectively */
+       u8 ssid_len;
+       u8 supp_rates_len;
+       u8 fh_params_len;
+       u8 ds_params_len;
+       u8 cf_params_len;
+       u8 tim_len;
+       u8 ibss_params_len;
+       u8 challenge_len;
+       u8 wpa_len;
+       u8 rsn_len;
+       u8 erp_info_len;
+       u8 ext_supp_rates_len;
+       u8 wmm_info_len;
        u8 wmm_param_len;
-       u8 *tspec;
-       u8 tspec_len;
 };
 
-typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
 
-
-static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
-                                      struct ieee802_11_elems *elems)
+static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
+                                           struct ieee802_11_elems *elems)
 {
        size_t left = len;
        u8 *pos = start;
@@ -181,34 +173,17 @@ static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
                        if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
                            pos[2] == 0xf2) {
                                /* Microsoft OUI (00:50:F2) */
-                               if (pos[3] == WIFI_OUI_TYPE_WPA) {
+                               if (pos[3] == 1) {
                                        /* OUI Type 1 - WPA IE */
                                        elems->wpa = pos;
                                        elems->wpa_len = elen;
-                               } else if (elen >= 5 &&
-                                          pos[3] == WIFI_OUI_TYPE_WMM) {
-                                       switch (pos[4]) {
-                                       case WIFI_OUI_STYPE_WMM_INFO:
+                               } else if (elen >= 5 && pos[3] == 2) {
+                                       if (pos[4] == 0) {
                                                elems->wmm_info = pos;
                                                elems->wmm_info_len = elen;
-                                               break;
-                                       case WIFI_OUI_STYPE_WMM_PARAM:
+                                       } else if (pos[4] == 1) {
                                                elems->wmm_param = pos;
                                                elems->wmm_param_len = elen;
-                                               break;
-                                       case WIFI_OUI_STYPE_WMM_TSPEC:
-                                               if (elen != 61) {
-                                                       printk(KERN_ERR "Wrong "
-                                                              "TSPEC size.\n");
-                                                       break;
-                                               }
-                                               elems->tspec = pos + 6;
-                                               elems->tspec_len = elen - 6;
-                                               break;
-                                       default:
-                                               //printk(KERN_ERR "Unsupported "
-                                               //       "WiFi OUI %d\n", pos[4]);
-                                               break;
                                        }
                                }
                        }
@@ -225,22 +200,6 @@ static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->ext_supp_rates = pos;
                        elems->ext_supp_rates_len = elen;
                        break;
-               case WLAN_EID_HT_CAPABILITY:
-                       elems->ht_cap_param = pos;
-                       elems->ht_cap_param_len = elen;
-                       break;
-               case WLAN_EID_HT_EXTRA_INFO:
-                       elems->ht_extra_param = pos;
-                       elems->ht_extra_param_len = elen;
-                       break;
-               case WLAN_EID_TSPEC:
-                       if (elen != 55) {
-                               printk(KERN_ERR "Wrong TSPEC size.\n");
-                               break;
-                       }
-                       elems->tspec = pos;
-                       elems->tspec_len = elen;
-                       break;
                default:
 #if 0
                        printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
@@ -352,6 +311,50 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 }
 
 
+static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+       int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
+       u8 changes = 0;
+
+       if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+                              MAC_FMT ")\n",
+                              dev->name,
+                              use_protection ? "enabled" : "disabled",
+                              MAC_ARG(ifsta->bssid));
+               }
+               if (use_protection)
+                       sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
+               else
+                       sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
+               changes |= IEEE80211_ERP_CHANGE_PROTECTION;
+       }
+
+       if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: switched to %s barker preamble"
+                              " (BSSID=" MAC_FMT ")\n",
+                              dev->name,
+                              (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?
+                                       "short" : "long",
+                              MAC_ARG(ifsta->bssid));
+               }
+               if (preamble_mode)
+                       sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
+               else
+                       sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
+               changes |= IEEE80211_ERP_CHANGE_PREAMBLE;
+       }
+
+       if (changes)
+               ieee80211_erp_info_change_notify(dev, changes);
+}
+
+
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
                                         struct ieee80211_if_sta *ifsta)
 {
@@ -364,7 +367,7 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev,
                return;
 
        buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
-                               ifsta->assocresp_ies_len), GFP_ATOMIC);
+                               ifsta->assocresp_ies_len), GFP_KERNEL);
        if (!buf)
                return;
 
@@ -404,32 +407,48 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev,
 
 
 static void ieee80211_set_associated(struct net_device *dev,
-                                    struct ieee80211_if_sta *ifsta, int assoc)
+                                    struct ieee80211_if_sta *ifsta,
+                                    bool assoc)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        union iwreq_data wrqu;
 
-       if (ifsta->associated == assoc)
+       if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc)
                return;
 
-       ifsta->associated = assoc;
-
        if (assoc) {
                struct ieee80211_sub_if_data *sdata;
+               struct ieee80211_sta_bss *bss;
+
+               ifsta->flags |= IEEE80211_STA_ASSOCIATED;
+
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
                if (sdata->type != IEEE80211_IF_TYPE_STA)
                        return;
+
+               bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+               if (bss) {
+                       if (bss->has_erp_value)
+                               ieee80211_handle_erp_ie(dev, bss->erp_value);
+                       ieee80211_rx_bss_put(dev, bss);
+               }
+
                netif_carrier_on(dev);
-               ifsta->prev_bssid_set = 1;
+               ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
                memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
                memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
                ieee80211_sta_send_associnfo(dev, ifsta);
        } else {
+               ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
+
                netif_carrier_off(dev);
+               ieee80211_reset_erp_info(dev);
                memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
        }
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
        ifsta->last_probe = jiffies;
+       ieee80211_led_assoc(local, assoc);
 }
 
 static void ieee80211_set_disassoc(struct net_device *dev,
@@ -456,8 +475,8 @@ static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
        pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
        memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
        pkt_data->ifindex = sdata->dev->ifindex;
-       pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
-       pkt_data->do_not_encrypt = !encrypt;
+       if (!encrypt)
+               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
 
        dev_queue_xmit(skb);
 }
@@ -535,7 +554,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
        u16 capab;
        struct ieee80211_sta_bss *bss;
        int wmm = 0;
-       int ht_enabled = 0;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -559,8 +577,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
                        capab |= WLAN_CAPABILITY_PRIVACY;
                if (bss->wmm_ie) {
                        wmm = 1;
-
-                       ht_enabled = 1;
                }
                ieee80211_rx_bss_put(dev, bss);
        }
@@ -571,7 +587,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
        memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
        memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
 
-       if (ifsta->prev_bssid_set) {
+       if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
                skb_put(skb, 10);
                mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
                                                   IEEE80211_STYPE_REASSOC_REQ);
@@ -601,8 +617,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
        *pos++ = len;
        for (i = 0; i < len; i++) {
                int rate = mode->rates[i].rate;
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate /= 2;
                *pos++ = (u8) (rate / 5);
        }
 
@@ -612,8 +626,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
                *pos++ = mode->num_rates - len;
                for (i = len; i < mode->num_rates; i++) {
                        int rate = mode->rates[i].rate;
-                       if (mode->mode == MODE_ATHEROS_TURBO)
-                               rate /= 2;
                        *pos++ = (u8) (rate / 5);
                }
        }
@@ -623,7 +635,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
                memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
        }
 
-       if (wmm && ifsta->wmm_enabled) {
+       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                pos = skb_put(skb, 9);
                *pos++ = WLAN_EID_VENDOR_SPECIFIC;
                *pos++ = 7; /* len */
@@ -636,19 +648,9 @@ static void ieee80211_send_assoc(struct net_device *dev,
                *pos++ = 0;
        }
 
-       /* if low level driver supports 11n, fill in 11n IE */
-       if (ht_enabled && ifsta->ht_enabled && local->ops->get_ht_capab) {
-               pos = skb_put(skb, sizeof(struct ieee80211_ht_capability)+2);
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_capability);
-               memset(pos, 0, sizeof(struct ieee80211_ht_capability));
-               local->ops->get_ht_capab(local_to_hw(local),
-                       (struct ieee80211_ht_capability *)pos);
-       }
-
        kfree(ifsta->assocreq_ies);
        ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
-       ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_ATOMIC);
+       ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
        if (ifsta->assocreq_ies)
                memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
 
@@ -714,410 +716,14 @@ static void ieee80211_send_disassoc(struct net_device *dev,
 }
 
 
-static int ieee80211_ts_index(u8 direction)
-{
-       if (direction == WLAN_TSINFO_DOWNLINK ||
-           direction == WLAN_TSINFO_DIRECTLINK)
-               return STA_TS_DOWNLINK;
-       return STA_TS_UPLINK; /* UP and Bidirectional LINK */
-}
-
-
-void ieee80211_send_addts(struct net_device *dev,
-                         struct ieee80211_if_sta *ifsta,
-                         struct ieee80211_elem_tspec *tspec)
-{
-       struct ieee80211_mgmt *mgmt;
-       struct sk_buff *skb;
-       static u8 token;
-       struct ieee80211_elem_tspec *ptspec;
-       u8 *pos;
-
-       skb = dev_alloc_skb(sizeof(*mgmt) + sizeof(*tspec));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for addts "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.addts_req));
-       mgmt->u.action.category = WLAN_CATEGORY_QOS;
-       mgmt->u.action.u.addts_req.action_code = WLAN_ACTION_QOS_ADDTS_REQ;
-       mgmt->u.action.u.addts_req.dialog_token = ++token % 127;
-
-       skb_put(skb, 2 + sizeof(*tspec));
-       pos = mgmt->u.action.u.addts_req.variable;
-       pos[0] = WLAN_EID_TSPEC;
-       pos[1] = sizeof(*tspec);
-       pos += 2;
-       ptspec = (struct ieee80211_elem_tspec *)pos;
-       memcpy(ptspec, tspec, sizeof(*tspec));
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-void wmm_send_addts(struct net_device *dev,
-                   struct ieee80211_if_sta *ifsta,
-                   struct ieee80211_elem_tspec *tspec)
-{
-       struct ieee80211_mgmt *mgmt;
-       struct sk_buff *skb;
-       static u8 token;
-       struct ieee80211_elem_tspec *ptspec;
-       u8 *pos;
-
-       skb = dev_alloc_skb(sizeof(*mgmt) + 2 + 6 + sizeof(*tspec));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for addts "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.wme_action));
-       mgmt->u.action.category = WLAN_CATEGORY_WMM;
-       mgmt->u.action.u.wme_action.action_code = WLAN_ACTION_QOS_ADDTS_REQ;
-       mgmt->u.action.u.wme_action.dialog_token = ++token % 127;
-       mgmt->u.action.u.wme_action.status_code = 0;
-
-       skb_put(skb, 2 + 6 + sizeof(*tspec));
-       pos = mgmt->u.action.u.wme_action.variable;
-       pos[0] = WLAN_EID_GENERIC;
-       pos[1] = 61;
-       pos += 2;
-       pos[0] = 0x00; pos[1] = 0x50; pos[2] = 0xf2; /* Wi-Fi OUI (00:50:F2)*/
-       pos += 3;
-       pos[0] = WIFI_OUI_TYPE_WMM;
-       pos[1] = WIFI_OUI_STYPE_WMM_TSPEC;
-       pos[2] = 1; /* Version */
-       pos += 3;
-       ptspec = (struct ieee80211_elem_tspec *)pos;
-       memcpy(ptspec, tspec, sizeof(*tspec));
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-void ieee80211_send_delts(struct net_device *dev,
-                         struct ieee80211_if_sta *ifsta,
-                         struct ieee80211_elem_tspec *tp)
-{
-       struct ieee80211_mgmt *mgmt;
-       struct sk_buff *skb;
-       u8 tsid = IEEE80211_TSINFO_TSID(tp->ts_info);
-       u8 direction = IEEE80211_TSINFO_DIR(tp->ts_info);
-       u16 medium_time = le16_to_cpu(tp->medium_time);
-       u8 index = ieee80211_ts_index(direction);
-
-       if (ifsta->ts_data[tsid][index].status == TS_STATUS_UNUSED) {
-               printk(KERN_DEBUG "%s: Trying to delete an ACM disabled TS "
-                      "(%u:%u)\n", dev->name, tsid, direction);
-               return;
-       }
-       skb = dev_alloc_skb(sizeof(*mgmt));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for delts "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       /* recompute admitted time */
-       ifsta->ts_data[tsid][index].admitted_time_usec -=
-               ifsta->dot11EDCAAveragingPeriod * medium_time * 32;
-       if ((s32)(ifsta->ts_data[tsid][index].admitted_time_usec) < 0)
-               ifsta->ts_data[tsid][index].admitted_time_usec = 0;
-
-       ifsta->ts_data[tsid][index].status = TS_STATUS_INACTIVE;
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.delts));
-       mgmt->u.action.category = WLAN_CATEGORY_QOS;
-       mgmt->u.action.u.delts.action_code = WLAN_ACTION_QOS_DELTS;
-       mgmt->u.action.u.delts.reason_code = 0;
-       memset(&mgmt->u.action.u.delts.ts_info, 0,
-                       sizeof(struct ieee80211_ts_info));
-
-       IEEE80211_SET_TSINFO_TSID(tp->ts_info, tsid);
-       IEEE80211_SET_TSINFO_DIR(tp->ts_info, direction);
-       IEEE80211_SET_TSINFO_POLICY(tp->ts_info, WLAN_TSINFO_EDCA);
-       IEEE80211_SET_TSINFO_APSD(tp->ts_info, WLAN_TSINFO_PSB_LEGACY);
-       IEEE80211_SET_TSINFO_UP(tp->ts_info, ifsta->ts_data[tsid][index].up);
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-void wmm_send_delts(struct net_device *dev,
-                   struct ieee80211_if_sta *ifsta,
-                   struct ieee80211_elem_tspec *tp)
-{
-       struct ieee80211_mgmt *mgmt;
-       struct ieee80211_elem_tspec *tspec;
-       struct sk_buff *skb;
-       u8 tsid = IEEE80211_TSINFO_TSID(tp->ts_info);
-       u8 direction = IEEE80211_TSINFO_DIR(tp->ts_info);
-       u16 medium_time = le16_to_cpu(tp->medium_time);
-       u8 index = ieee80211_ts_index(direction);
-       u8 *pos;
-
-       if (ifsta->ts_data[tsid][index].status == TS_STATUS_UNUSED) {
-               printk(KERN_DEBUG "%s: Tring to delete a non-Actived TS "
-                      "(%u %u)\n", dev->name, tsid, direction);
-               return;
-       }
-       skb = dev_alloc_skb(sizeof(*mgmt) + 2 + 6 + sizeof(*tspec));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for delts "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       /* recompute admitted time */
-       ifsta->ts_data[tsid][index].admitted_time_usec -=
-               ifsta->dot11EDCAAveragingPeriod * medium_time * 32;
-       if ((s32)(ifsta->ts_data[tsid][index].admitted_time_usec < 0))
-               ifsta->ts_data[tsid][index].admitted_time_usec = 0;
-
-       ifsta->ts_data[tsid][index].status = TS_STATUS_INACTIVE;
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.wme_action));
-       mgmt->u.action.category = WLAN_CATEGORY_WMM;
-       mgmt->u.action.u.wme_action.action_code = WLAN_ACTION_QOS_DELTS;
-       mgmt->u.action.u.wme_action.dialog_token = 0;
-       mgmt->u.action.u.wme_action.status_code = 0;
-
-       skb_put(skb, 2 + 6 + sizeof(*tspec));
-       pos = mgmt->u.action.u.wme_action.variable;
-       pos[0] = WLAN_EID_GENERIC;
-       pos[1] = 61;
-       pos += 2;
-       pos[0] = 0x00; pos[1] = 0x50; pos[2] = 0xf2; /* Wi-Fi OUI (00:50:F2)*/
-       pos += 3;
-       pos[0] = WIFI_OUI_TYPE_WMM;
-       pos[1] = WIFI_OUI_STYPE_WMM_TSPEC;
-       pos[2] = 1; /* Version */
-       pos += 3;
-       tspec = (struct ieee80211_elem_tspec *)pos;
-       memset(tspec, 0, sizeof(*tspec));
-
-       IEEE80211_SET_TSINFO_TSID(tspec->ts_info, tsid);
-       IEEE80211_SET_TSINFO_DIR(tspec->ts_info, direction);
-       IEEE80211_SET_TSINFO_POLICY(tspec->ts_info, WLAN_TSINFO_EDCA);
-       IEEE80211_SET_TSINFO_APSD(tspec->ts_info, WLAN_TSINFO_PSB_LEGACY);
-       IEEE80211_SET_TSINFO_UP(tspec->ts_info, ifsta->ts_data[tsid][index].up);
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-void ieee80211_send_dls_req(struct net_device *dev,
-                           struct ieee80211_if_sta *ifsta,
-                           u8 *addr, u16 timeout)
-{
-       struct ieee80211_hw_mode *mode;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u8 *pos, *supp_rates, *esupp_rates = NULL;
-       int i;
-
-       skb = dev_alloc_skb(sizeof(*mgmt) + 200 /* rates + ext_rates Size */);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for DLS REQ "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.dls_req));
-       mgmt->u.action.category = WLAN_CATEGORY_DLS;
-       mgmt->u.action.u.dls_req.action_code = WLAN_ACTION_DLS_REQ;
-       memcpy(mgmt->u.action.u.dls_req.dest, addr, ETH_ALEN);
-       memcpy(mgmt->u.action.u.dls_req.src, dev->dev_addr, ETH_ALEN);
-       mgmt->u.action.u.dls_req.capab_info = cpu_to_le16(ifsta->ap_capab);
-       mgmt->u.action.u.dls_req.timeout = cpu_to_le16(timeout);
-
-       /* Add supported rates and extended supported rates */
-       supp_rates = skb_put(skb, 2);
-       supp_rates[0] = WLAN_EID_SUPP_RATES;
-       supp_rates[1] = 0;
-       mode = local->oper_hw_mode;
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-               if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
-                       continue;
-               if (esupp_rates) {
-                       pos = skb_put(skb, 1);
-                       esupp_rates[1]++;
-               } else if (supp_rates[1] == 8) {
-                       esupp_rates = skb_put(skb, 3);
-                       esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-                       esupp_rates[1] = 1;
-                       pos = &esupp_rates[2];
-               } else {
-                       pos = skb_put(skb, 1);
-                       supp_rates[1]++;
-               }
-               if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
-                       *pos = rate->rate / 10;
-               else
-                       *pos = rate->rate / 5;
-       }
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-static void ieee80211_send_dls_resp(struct net_device *dev,
-                                   struct ieee80211_if_sta *ifsta,
-                                   u8 *mac_addr, u16 status)
-{
-       struct ieee80211_hw_mode *mode;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u8 *pos, *supp_rates, *esupp_rates = NULL;
-       int i;
-
-       skb = dev_alloc_skb(sizeof(*mgmt) + 200 /* rates + ext_rates Size */);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for dls resp "
-                      "frame\n", dev->name);
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.dls_resp));
-       mgmt->u.action.category = WLAN_CATEGORY_DLS;
-       mgmt->u.action.u.dls_resp.action_code = WLAN_ACTION_DLS_RESP;
-       memcpy(mgmt->u.action.u.dls_resp.dest, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->u.action.u.dls_resp.src, mac_addr, ETH_ALEN);
-       mgmt->u.action.u.dls_resp.status_code = cpu_to_le16(status);
-
-       if (!mgmt->u.action.u.dls_resp.status_code) {
-               ieee80211_sta_tx(dev, skb, 0);
-               return;
-       }
-
-       /* Add capability information */
-       pos = skb_put(skb, 2);
-       *(__le16 *)pos = cpu_to_le16(ifsta->ap_capab);
-
-       /* Add supported rates and extended supported rates */
-       supp_rates = skb_put(skb, 2);
-       supp_rates[0] = WLAN_EID_SUPP_RATES;
-       supp_rates[1] = 0;
-       mode = local->oper_hw_mode;
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-               if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
-                       continue;
-               if (esupp_rates) {
-                       pos = skb_put(skb, 1);
-                       esupp_rates[1]++;
-               } else if (supp_rates[1] == 8) {
-                       esupp_rates = skb_put(skb, 3);
-                       esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-                       esupp_rates[1] = 1;
-                       pos = &esupp_rates[2];
-               } else {
-                       pos = skb_put(skb, 1);
-                       supp_rates[1]++;
-               }
-               if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
-                       *pos = rate->rate / 10;
-               else
-                       *pos = rate->rate / 5;
-       }
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
-void ieee80211_send_dls_teardown(struct net_device *dev,
-                                struct ieee80211_if_sta *ifsta,
-                                u8 *mac_addr, u16 reason)
-{
-       struct ieee80211_mgmt *mgmt;
-       struct sk_buff *skb;
-
-       skb = dev_alloc_skb(sizeof(*mgmt));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for DLS "
-                      "Teardown frame\n", dev->name);
-               return;
-       }
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.dls_teardown));
-       mgmt->u.action.category = WLAN_CATEGORY_DLS;
-       mgmt->u.action.u.dls_teardown.action_code = WLAN_ACTION_DLS_TEARDOWN;
-       memcpy(mgmt->u.action.u.dls_teardown.dest, mac_addr, ETH_ALEN);
-       memcpy(mgmt->u.action.u.dls_teardown.src, dev->dev_addr, ETH_ALEN);
-       mgmt->u.action.u.dls_teardown.reason_code = cpu_to_le16(reason);
-
-       ieee80211_sta_tx(dev, skb, 0);
-}
-
-
 static int ieee80211_privacy_mismatch(struct net_device *dev,
                                      struct ieee80211_if_sta *ifsta)
 {
        struct ieee80211_sta_bss *bss;
        int res = 0;
 
-       if (!ifsta || ifsta->mixed_cell ||
-           ifsta->key_mgmt != IEEE80211_KEY_MGMT_NONE)
+       if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
+           ifsta->key_management_enabled)
                return 0;
 
        bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
@@ -1185,22 +791,20 @@ static void ieee80211_associated(struct net_device *dev,
                disassoc = 0;
                if (time_after(jiffies,
                               sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
-                       if (ifsta->probereq_poll) {
+                       if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
                                printk(KERN_DEBUG "%s: No ProbeResp from "
                                       "current AP " MAC_FMT " - assume out of "
                                       "range\n",
                                       dev->name, MAC_ARG(ifsta->bssid));
                                disassoc = 1;
-                               sta_info_free(sta, 0);
-                               ifsta->probereq_poll = 0;
-                       } else {
+                               sta_info_free(sta);
+                       } else
                                ieee80211_send_probe_req(dev, ifsta->bssid,
                                                         local->scan_ssid,
                                                         local->scan_ssid_len);
-                               ifsta->probereq_poll = 1;
-                       }
+                       ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
                } else {
-                       ifsta->probereq_poll = 0;
+                       ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
                        if (time_after(jiffies, ifsta->last_probe +
                                       IEEE80211_PROBE_INTERVAL)) {
                                ifsta->last_probe = jiffies;
@@ -1280,10 +884,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                        pos = skb_put(skb, 1);
                        supp_rates[1]++;
                }
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       *pos = rate->rate / 10;
-               else
-                       *pos = rate->rate / 5;
+               *pos = rate->rate / 5;
        }
 
        ieee80211_sta_tx(dev, skb, 0);
@@ -1294,7 +895,7 @@ static int ieee80211_sta_wep_configured(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (!sdata || !sdata->default_key ||
-           sdata->default_key->alg != ALG_WEP)
+           sdata->default_key->conf.alg != ALG_WEP)
                return 0;
        return 1;
 }
@@ -1304,7 +905,7 @@ static void ieee80211_auth_completed(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta)
 {
        printk(KERN_DEBUG "%s: authenticated\n", dev->name);
-       ifsta->authenticated = 1;
+       ifsta->flags |= IEEE80211_STA_AUTHENTICATED;
        ieee80211_associate(dev, ifsta);
 }
 
@@ -1491,7 +1092,7 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
               " (reason=%d)\n",
               dev->name, MAC_ARG(mgmt->sa), reason_code);
 
-       if (ifsta->authenticated) {
+       if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
                printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
        }
 
@@ -1504,7 +1105,7 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
        }
 
        ieee80211_set_disassoc(dev, ifsta, 1);
-       ifsta->authenticated = 0;
+       ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED;
 }
 
 
@@ -1536,7 +1137,7 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
               " (reason=%d)\n",
               dev->name, MAC_ARG(mgmt->sa), reason_code);
 
-       if (ifsta->associated)
+       if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
                printk(KERN_DEBUG "%s: disassociated\n", dev->name);
 
        if (ifsta->state == IEEE80211_ASSOCIATED) {
@@ -1605,8 +1206,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
                       dev->name, status_code);
-               if (status_code == WLAN_STATUS_REASSOC_NO_ASSOC)
-                       ifsta->prev_bssid_set = 0;
+               /* if this was a reassociation, ensure we try a "full"
+                * association next time. This works around some broken APs
+                * which do not correctly reject reassociation requests. */
+               ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
                return;
        }
 
@@ -1624,13 +1227,25 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
                return;
        }
 
+       /* it probably doesn't, but if the frame includes an ERP value then
+        * update our stored copy */
+       if (elems.erp_info && elems.erp_info_len >= 1) {
+               struct ieee80211_sta_bss *bss
+                       = ieee80211_rx_bss_get(dev, ifsta->bssid);
+               if (bss) {
+                       bss->erp_value = elems.erp_info[0];
+                       bss->has_erp_value = 1;
+                       ieee80211_rx_bss_put(dev, bss);
+               }
+       }
+
        printk(KERN_DEBUG "%s: associated\n", dev->name);
        ifsta->aid = aid;
        ifsta->ap_capab = capab_info;
 
        kfree(ifsta->assocresp_ies);
        ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);
-       ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_ATOMIC);
+       ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL);
        if (ifsta->assocresp_ies)
                memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
 
@@ -1640,7 +1255,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        sta = sta_info_get(local, ifsta->bssid);
        if (!sta) {
                struct ieee80211_sta_bss *bss;
-               sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC);
+               sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL);
                if (!sta) {
                        printk(KERN_DEBUG "%s: failed to add STA entry for the"
                               " AP\n", dev->name);
@@ -1656,46 +1271,27 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        }
 
        sta->dev = dev;
-       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
-       sta->assoc_ap = 1;
+       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP;
 
        rates = 0;
        mode = local->oper_hw_mode;
        for (i = 0; i < elems.supp_rates_len; i++) {
                int rate = (elems.supp_rates[i] & 0x7f) * 5;
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate *= 2;
                for (j = 0; j < mode->num_rates; j++)
                        if (mode->rates[j].rate == rate)
                                rates |= BIT(j);
        }
        for (i = 0; i < elems.ext_supp_rates_len; i++) {
                int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate *= 2;
                for (j = 0; j < mode->num_rates; j++)
                        if (mode->rates[j].rate == rate)
                                rates |= BIT(j);
        }
        sta->supp_rates = rates;
 
-       if (elems.ht_extra_param && elems.ht_cap_param && elems.wmm_param &&
-           ifsta->ht_enabled && local->ops->conf_ht){
-               int rc;
-
-               rc = local->ops->conf_ht(local_to_hw(local),
-                                        (struct ieee80211_ht_capability *)
-                                        elems.ht_cap_param,
-                                        (struct ieee80211_ht_additional_info *)
-                                        elems.ht_extra_param);
-               if (!rc)
-                       sta->flags |= WLAN_STA_HT;
-       }
-
-
        rate_control_rate_init(sta, local);
 
-       if (elems.wmm_param && ifsta->wmm_enabled) {
+       if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                sta->flags |= WLAN_STA_WME;
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
@@ -1707,258 +1303,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        ieee80211_associated(dev, ifsta);
 }
 
-static u32 calculate_mpdu_exchange_time(struct ieee80211_local *local,
-                                       struct ieee80211_elem_tspec *tspec)
-{
-       /*
-        * FIXME: MPDUExchangeTime = duration(Nominal MSDU Size, Min PHY Rate) +
-        *                           SIFS + ACK duration
-        */
-       int extra = 0; /* SIFS + ACK */
-
-       switch (local->hw.conf.phymode) {
-       case MODE_IEEE80211A:
-               extra = 16 + 24;
-               break;
-       case MODE_IEEE80211B:
-               extra = 10 + 203;
-               break;
-       case MODE_IEEE80211G:
-       default:
-               extra = 10 + 30;
-               break;
-       }
-       return (tspec->nominal_msdu_size * 8) /
-               (tspec->min_phy_rate / 1000000) + extra;
-}
-
-static void sta_update_tspec(struct ieee80211_local *local,
-                            struct ieee80211_if_sta *ifsta,
-                            int action, struct ieee80211_elem_tspec *tspec)
-{
-       u8 tsid = IEEE80211_TSINFO_TSID(tspec->ts_info);
-       u8 index = ieee80211_ts_index(IEEE80211_TSINFO_DIR(tspec->ts_info));
-
-       switch (action) {
-       case WLAN_ACTION_QOS_ADDTS_RESP:
-               ifsta->ts_data[tsid][index].status = TS_STATUS_ACTIVE;
-               ifsta->ts_data[tsid][index].up =
-                       IEEE80211_TSINFO_UP(tspec->ts_info);
-               ifsta->ts_data[tsid][index].used_time_usec = 0;
-               ifsta->ts_data[tsid][index].admitted_time_usec +=
-                   ifsta->dot11EDCAAveragingPeriod * tspec->medium_time * 32;
-               ifsta->MPDUExchangeTime =
-                       calculate_mpdu_exchange_time(local, tspec);
-               break;
-       case WLAN_ACTION_QOS_DELTS:
-               ifsta->ts_data[tsid][index].status = TS_STATUS_INACTIVE;
-               ifsta->ts_data[tsid][index].used_time_usec = 0;
-               ifsta->ts_data[tsid][index].admitted_time_usec -=
-                   ifsta->dot11EDCAAveragingPeriod * tspec->medium_time * 32;
-               if (ifsta->ts_data[tsid][index].admitted_time_usec < 0)
-                       ifsta->ts_data[tsid][index].admitted_time_usec = 0;
-               ifsta->MPDUExchangeTime = 0;
-               break;
-       default:
-               printk(KERN_ERR "%s: invalid action type %d\n", __FUNCTION__,
-                      action);
-               break;
-       }
-}
-
-static void sta_parse_tspec(struct net_device *dev,
-                           struct ieee80211_if_sta *ifsta,
-                           struct ieee80211_mgmt *mgmt, size_t len, u8 prefix,
-                           struct ieee80211_elem_tspec *tspec)
-{
-       struct ieee802_11_elems elems;
-       u8 *pos;
-
-       /*
-       printk(KERN_DEBUG "Dialog_token: %d, TID: %u, Direction: %u, PSB: %d, "
-              "UP: %d\n", mgmt->u.action.u.wme_action.dialog_token,
-              IEEE80211_TSINFO_TSID(tspec->ts_info),
-              IEEE80211_TSINFO_DIR(tspec->ts_info),
-              IEEE80211_TSINFO_APSD(tspec->ts_info),
-              IEEE80211_TSINFO_UP(tspec->ts_info));
-       */
-
-       if (mgmt->u.action.category == WLAN_CATEGORY_QOS)
-               pos = mgmt->u.action.u.addts_resp.variable + prefix;
-       else
-               pos = mgmt->u.action.u.wme_action.variable + prefix;
-
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
-           == ParseFailed) {
-               printk(KERN_DEBUG "%s: failed to parse TSPEC\n", dev->name);
-               return;
-       }
-       memcpy(tspec, elems.tspec, sizeof(*tspec));
-}
-
-int dls_link_status(struct ieee80211_local *local, u8 *addr)
-{
-       struct sta_info *dls;
-       int ret = DLS_STATUS_NOLINK;
-
-       if ((dls = dls_info_get(local, addr)) != NULL) {
-               ret = dls->dls_status;
-               sta_info_put(dls);
-       }
-       return ret;
-}
-
-static void sta_process_dls_req(struct net_device *dev,
-                               struct ieee80211_if_sta *ifsta,
-                               struct ieee80211_mgmt *mgmt, size_t len)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *dls;
-       u8 *src = mgmt->u.action.u.dls_req.src;
-       struct ieee802_11_elems elems;
-       struct ieee80211_rate *rates;
-       size_t baselen, num_rates;
-       int i, j;
-       struct ieee80211_hw_mode *mode;
-       u32 supp_rates = 0;
-
-       printk(KERN_DEBUG "Receive DLS request from "
-              "%02X:%02X:%02X:%02X:%02X:%02X\n",
-              src[0], src[1], src[2], src[3], src[4], src[5]);
-
-       baselen = (u8 *)mgmt->u.action.u.dls_req.variable - (u8 *)mgmt;
-       if (baselen > len)
-               return;
-
-       if (ieee802_11_parse_elems(mgmt->u.action.u.dls_req.variable,
-                                  len - baselen, &elems) == ParseFailed) {
-               printk(KERN_ERR "DLS Parse support rates failed.\n");
-               return;
-       }
-       mode = local->sta_scanning ?
-              local->scan_hw_mode : local->oper_hw_mode;
-       rates = mode->rates;
-       num_rates = mode->num_rates;
-
-       for (i = 0; i < elems.supp_rates_len + elems.ext_supp_rates_len; i++) {
-               u8 rate = 0;
-               if (i < elems.supp_rates_len)
-                       rate = elems.supp_rates[i];
-               else if (elems.ext_supp_rates)
-                       rate = elems.ext_supp_rates[i - elems.supp_rates_len];
-               rate = 5 * (rate & 0x7f);
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate *= 2;
-               for (j = 0; j < num_rates; j++)
-                       if (rates[j].rate == rate)
-                               supp_rates |= BIT(j);
-       }
-       if (supp_rates == 0) {
-               /* Send DLS failed Response to the peer because
-                * the supported rates are mismatch */
-               ieee80211_send_dls_resp(dev, ifsta, src,
-                                       WLAN_REASON_QSTA_NOT_USE);
-               return;
-       }
-
-       dls = dls_info_get(local, src);
-       if (!dls)
-               dls = sta_info_add(local, dev, src, GFP_ATOMIC);
-       if (!dls)
-               return;
-
-       dls->dls_status = DLS_STATUS_OK;
-       dls->dls_timeout = le16_to_cpu(mgmt->u.action.u.dls_req.timeout);
-       dls->supp_rates = supp_rates;
-
-       /* Send DLS successful Response to the peer */
-       ieee80211_send_dls_resp(dev, ifsta, src, 0);
-}
-
-
-static void sta_process_dls_resp(struct net_device *dev,
-                                struct ieee80211_if_sta *ifsta,
-                                struct ieee80211_mgmt *mgmt, size_t len)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *dls;
-       u8 *src = mgmt->u.action.u.dls_resp.src;
-       struct ieee802_11_elems elems;
-       struct ieee80211_rate *rates;
-       size_t baselen, num_rates;
-       int i, j;
-       struct ieee80211_hw_mode *mode;
-       u32 supp_rates = 0;
-
-       printk(KERN_DEBUG "Receive DLS response from "
-              "%02X:%02X:%02X:%02X:%02X:%02X\n",
-              src[0], src[1], src[2], src[3], src[4], src[5]);
-
-       if (mgmt->u.action.u.dls_resp.status_code) {
-               printk(KERN_ERR "DLS setup refused by peer. Reason %d\n",
-                      mgmt->u.action.u.dls_resp.status_code);
-               return;
-       }
-
-       baselen = (u8 *)mgmt->u.action.u.dls_resp.variable - (u8 *)mgmt;
-       if (baselen > len)
-               return;
-
-       if (ieee802_11_parse_elems(mgmt->u.action.u.dls_resp.variable,
-                                  len - baselen, &elems) == ParseFailed) {
-               printk(KERN_ERR "DLS Parse support rates failed.\n");
-               return;
-       }
-       mode = local->sta_scanning ?
-              local->scan_hw_mode : local->oper_hw_mode;
-       rates = mode->rates;
-       num_rates = mode->num_rates;
-
-       for (i = 0; i < elems.supp_rates_len + elems.ext_supp_rates_len; i++) {
-               u8 rate = 0;
-               if (i < elems.supp_rates_len)
-                       rate = elems.supp_rates[i];
-               else if (elems.ext_supp_rates)
-                       rate = elems.ext_supp_rates[i - elems.supp_rates_len];
-               rate = 5 * (rate & 0x7f);
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate *= 2;
-               for (j = 0; j < num_rates; j++)
-                       if (rates[j].rate == rate)
-                               supp_rates |= BIT(j);
-       }
-
-       dls = dls_info_get(local, src);
-       if (!dls)
-               dls = sta_info_add(local, dev, src, GFP_ATOMIC);
-       if (!dls)
-               return;
-
-       dls->supp_rates = supp_rates;
-       dls->dls_status = DLS_STATUS_OK;
-       sta_info_put(dls);
-}
-
-
-static void sta_process_dls_teardown(struct net_device *dev,
-                                    struct ieee80211_if_sta *ifsta,
-                                    struct ieee80211_mgmt *mgmt, size_t len)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       u8 *src = mgmt->u.action.u.dls_teardown.src;
-       struct sta_info *dls;
-
-       printk(KERN_DEBUG "DLS Teardown received from "
-              "%02X:%02X:%02X:%02X:%02X:%02X. Reason %d\n",
-              src[0], src[1], src[2], src[3], src[4], src[5],
-              mgmt->u.action.u.dls_teardown.reason_code);
-
-       dls = dls_info_get(local, src);
-       if (dls)
-               sta_info_free(dls, 0);
-       return;
-}
-
 
 /* Caller must hold local->sta_bss_lock */
 static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
@@ -1998,10 +1342,9 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
 
-       bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+       bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
        if (!bss)
                return NULL;
-       memset(bss, 0, sizeof(*bss));
        atomic_inc(&bss->users);
        atomic_inc(&bss->users);
        memcpy(bss->bssid, bssid, ETH_ALEN);
@@ -2040,7 +1383,6 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
        kfree(bss->wpa_ie);
        kfree(bss->rsn_ie);
        kfree(bss->wmm_ie);
-       kfree(bss->ht_ie);
        kfree(bss);
 }
 
@@ -2160,8 +1502,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                                rate = elems.ext_supp_rates
                                        [i - elems.supp_rates_len];
                        own_rate = 5 * (rate & 0x7f);
-                       if (mode->mode == MODE_ATHEROS_TURBO)
-                               own_rate *= 2;
                        for (j = 0; j < num_rates; j++)
                                if (rates[j].rate == own_rate)
                                        supp_rates |= BIT(j);
@@ -2213,6 +1553,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                return;
        }
 
+       /* save the ERP value so that it is available at association time */
+       if (elems.erp_info && elems.erp_info_len >= 1) {
+               bss->erp_value = elems.erp_info[0];
+               bss->has_erp_value = 1;
+       }
+
        bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
        bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
        if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
@@ -2287,23 +1633,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                bss->wmm_ie_len = 0;
        }
 
-       if (elems.ht_cap_param &&
-           (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_param_len ||
-            memcmp(bss->ht_ie, elems.ht_cap_param, elems.ht_cap_param_len))) {
-               if (bss->ht_ie)
-                       kfree(bss->ht_ie);
-               bss->ht_ie = kmalloc(elems.ht_cap_param_len + 2, GFP_ATOMIC);
-               if (bss->ht_ie) {
-                       memcpy(bss->ht_ie, elems.ht_cap_param - 2,
-                              elems.ht_cap_param_len + 2);
-                       bss->ht_ie_len = elems.ht_cap_param_len + 2;
-               } else
-                       bss->ht_ie_len = 0;
-       } else if (!elems.ht_cap_param && bss->ht_ie) {
-               kfree(bss->ht_ie);
-               bss->ht_ie = NULL;
-               bss->ht_ie_len = 0;
-       }
 
        bss->hw_mode = rx_status->phymode;
        bss->channel = channel;
@@ -2345,10 +1674,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
                                     size_t len,
                                     struct ieee80211_rx_status *rx_status)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_sta *ifsta;
-       int use_protection;
        size_t baselen;
        struct ieee802_11_elems elems;
 
@@ -2359,7 +1686,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
                return;
        ifsta = &sdata->u.sta;
 
-       if (!ifsta->associated ||
+       if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) ||
            memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
@@ -2372,25 +1699,10 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
                                   &elems) == ParseFailed)
                return;
 
-       use_protection = 0;
-       if (elems.erp_info && elems.erp_info_len >= 1) {
-               use_protection =
-                       (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
-       }
-
-       if (use_protection != !!ifsta->use_protection) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
-                              MAC_FMT ")\n",
-                              dev->name,
-                              use_protection ? "enabled" : "disabled",
-                              MAC_ARG(ifsta->bssid));
-               }
-               ifsta->use_protection = use_protection ? 1 : 0;
-               local->cts_protect_erp_frames = use_protection;
-       }
+       if (elems.erp_info && elems.erp_info_len >= 1)
+               ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
 
-       if (elems.wmm_param && ifsta->wmm_enabled) {
+       if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
        }
@@ -2453,7 +1765,7 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        }
 
        /* Reply with ProbeResp */
-       skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+       skb = skb_copy(ifsta->probe_resp, GFP_KERNEL);
        if (!skb)
                return;
 
@@ -2466,172 +1778,6 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        ieee80211_sta_tx(dev, skb, 0);
 }
 
-static void ieee80211_send_addba_resp(struct net_device *dev,
-                                     struct ieee80211_mgmt *mgmt_src,
-                                     size_t len,
-                                     u16 status)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-
-       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer "
-                      "for addba resp frame\n", dev->name);
-               return;
-       }
-
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                          IEEE80211_STYPE_ACTION);
-
-       skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
-       mgmt->u.action.category = WLAN_CATEGORY_BACK;
-       mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
-       mgmt->u.action.u.addba_resp.dialog_token =
-               mgmt_src->u.action.u.addba_req.dialog_token;
-       mgmt->u.action.u.addba_resp.capab =
-               mgmt_src->u.action.u.addba_req.capab;
-       mgmt->u.action.u.addba_resp.timeout =
-               mgmt_src->u.action.u.addba_req.timeout;
-       mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
-
-       ieee80211_sta_tx(dev, skb, 0);
-
-       return;
-}
-
-static void ieee80211_rx_mgmt_action(struct net_device *dev,
-                                    struct ieee80211_if_sta *ifsta,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len)
-{
-       u8 prefix = 0;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_elem_tspec tspec;
-
-       if (len < IEEE80211_MIN_ACTION_SIZE)
-               return;
-
-       switch (mgmt->u.action.category) {
-       case WLAN_CATEGORY_QOS:
-       case WLAN_CATEGORY_WMM:
-               if (len < 24 + 4) {
-                       printk(KERN_DEBUG "%s: too short (%zd) QoS category "
-                              "frame received from " MAC_FMT " - ignored\n",
-                              dev->name, len, MAC_ARG(mgmt->sa));
-                       return;
-               }
-               switch (mgmt->u.action.u.wme_action.action_code) {
-               case WLAN_ACTION_QOS_ADDTS_REQ:
-                       printk(KERN_DEBUG "%s: WLAN_ACTION_QOS_ADDTS_REQ "
-                              "received in Non-AP STA mode!\n", dev->name);
-                       return;
-               case WLAN_ACTION_QOS_ADDTS_RESP:
-                       if (mgmt->u.action.u.wme_action.status_code == 47) {
-                               /* TODO: handle TS Delay */
-                               prefix = 6;
-                       }
-                       /* TODO: handle TCLAS, TCLAS Porcessing here */
-
-                       if (mgmt->u.action.u.wme_action.status_code == 0) {
-                               /* TODO: handle Schedule */
-                               sta_parse_tspec(dev, ifsta, mgmt, len,
-                                               prefix, &tspec);
-                               sta_update_tspec(local, ifsta,
-                                                WLAN_ACTION_QOS_ADDTS_RESP,
-                                                &tspec);
-                               mod_timer(&ifsta->admit_timer, jiffies +
-                                         ifsta->dot11EDCAAveragingPeriod * HZ);
-                       }
-                       break;
-               case WLAN_ACTION_QOS_DELTS:
-                       sta_parse_tspec(dev, ifsta, mgmt, len, prefix, &tspec);
-                       sta_update_tspec(local, ifsta,
-                                        WLAN_ACTION_QOS_DELTS, &tspec);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: unsupported QoS action code %d\n",
-                              dev->name,
-                              mgmt->u.action.u.wme_action.action_code);
-                       break;
-               }
-               break;
-
-       case WLAN_CATEGORY_DLS:
-               if (len < 24 + 16) {
-                       printk(KERN_DEBUG "%s: too short (%zd) DLS category "
-                              "frame received from " MAC_FMT " - ignored\n",
-                              dev->name, len, MAC_ARG(mgmt->sa));
-                       return;
-               }
-               switch (mgmt->u.action.u.dls_req.action_code) {
-               case WLAN_ACTION_DLS_REQ:
-                       sta_process_dls_req(dev, ifsta, mgmt, len);
-                       break;
-               case WLAN_ACTION_DLS_RESP:
-                       sta_process_dls_resp(dev, ifsta, mgmt, len);
-                       break;
-               case WLAN_ACTION_DLS_TEARDOWN:
-                       sta_process_dls_teardown(dev, ifsta, mgmt, len);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: unsupported DLS action code %d\n",
-                              dev->name, mgmt->u.action.u.dls_req.action_code);
-                       break;
-               }
-               break;
-
-       case WLAN_CATEGORY_BACK:
-               switch (mgmt->u.action.u.addba_req.action_code) {
-               case WLAN_ACTION_ADDBA_REQ:
-                       if (len < (IEEE80211_MIN_ACTION_SIZE +
-                                  sizeof(mgmt->u.action.u.addba_req)))
-                               break;
-                       if (!local->ops->handle_ba_action ||
-                           (local->ops->handle_ba_action(local_to_hw(local),
-                                                     mgmt)))
-                               ieee80211_send_addba_resp(dev, mgmt, len,
-                                               WLAN_STATUS_REQUEST_DECLINED);
-                       else
-                               ieee80211_send_addba_resp(dev, mgmt, len,
-                                                       WLAN_STATUS_SUCCESS);
-                       break;
-               case WLAN_ACTION_ADDBA_RESP:
-                       if (len < (IEEE80211_MIN_ACTION_SIZE +
-                                  sizeof(mgmt->u.action.u.addba_resp)))
-                               break;
-                       if (!local->ops->handle_ba_action)
-                               break;
-                       local->ops->handle_ba_action(local_to_hw(local), mgmt);
-                       break;
-               case WLAN_ACTION_DELBA:
-                       if (len < (IEEE80211_MIN_ACTION_SIZE +
-                                  sizeof(mgmt->u.action.u.delba)))
-                               break;
-
-                        if (!local->ops->handle_ba_action)
-                               break;
-
-                       local->ops->handle_ba_action(local_to_hw(local), mgmt);
-                       break;
-               default:
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-}
 
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
                           struct ieee80211_rx_status *rx_status)
@@ -2661,7 +1807,6 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
        case IEEE80211_STYPE_REASSOC_RESP:
        case IEEE80211_STYPE_DEAUTH:
        case IEEE80211_STYPE_DISASSOC:
-       case IEEE80211_STYPE_ACTION:
                skb_queue_tail(&ifsta->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifsta->work);
                return;
@@ -2719,9 +1864,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
        case IEEE80211_STYPE_DISASSOC:
                ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
                break;
-       case IEEE80211_STYPE_ACTION:
-               ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
-               break;
        }
 
        kfree_skb(skb);
@@ -2762,7 +1904,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
        int active = 0;
        struct sta_info *sta;
 
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        list_for_each_entry(sta, &local->sta_list, list) {
                if (sta->dev == dev &&
                    time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
@@ -2771,7 +1913,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
                        break;
                }
        }
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
 
        return active;
 }
@@ -2781,16 +1923,24 @@ static void ieee80211_sta_expire(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta, *tmp;
+       LIST_HEAD(tmp_list);
 
-       spin_lock_bh(&local->sta_lock);
+       write_lock_bh(&local->sta_lock);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
                if (time_after(jiffies, sta->last_rx +
                               IEEE80211_IBSS_INACTIVITY_LIMIT)) {
                        printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
                               "\n", dev->name, MAC_ARG(sta->addr));
-                       sta_info_free(sta, 1);
+                       __sta_info_get(sta);
+                       sta_info_remove(sta);
+                       list_add(&sta->list, &tmp_list);
                }
-       spin_unlock_bh(&local->sta_lock);
+       write_unlock_bh(&local->sta_lock);
+
+       list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
+               sta_info_free(sta);
+               sta_info_put(sta);
+       }
 }
 
 
@@ -2895,43 +2045,6 @@ void ieee80211_sta_work(struct work_struct *work)
 }
 
 
-void ieee80211_admit_refresh(unsigned long ptr)
-{
-       struct net_device *dev;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_sta *ifsta;
-       int i, j, find = 0;
-
-       dev = (struct net_device *) ptr;
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       ifsta = &sdata->u.sta;
-
-       for (i = 0; i < STA_TSID_NUM; i++) {
-               for (j = 0; j < STA_TSDIR_NUM; j++) {
-                       if ((ifsta->ts_data[i][j].status != TS_STATUS_ACTIVE) &&
-                           (ifsta->ts_data[i][j].status != TS_STATUS_THROTTLING))
-                               continue;
-                       find = 1;
-
-                       ifsta->ts_data[i][j].used_time_usec -=
-                               ifsta->ts_data[i][j].admitted_time_usec;
-                       if ((s32)(ifsta->ts_data[i][j].used_time_usec) < 0)
-                               ifsta->ts_data[i][j].used_time_usec = 0;
-
-                       ifsta->ts_data[i][j].status =
-                               (ifsta->ts_data[i][j].used_time_usec >=
-                                ifsta->ts_data[i][j].admitted_time_usec) ?
-                               TS_STATUS_THROTTLING :
-                               TS_STATUS_ACTIVE;
-               }
-       }
-
-       if (find)
-               mod_timer(&ifsta->admit_timer, jiffies +
-                         ifsta->dot11EDCAAveragingPeriod * HZ);
-}
-
-
 static void ieee80211_sta_reset_auth(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta)
 {
@@ -2956,7 +2069,8 @@ static void ieee80211_sta_reset_auth(struct net_device *dev,
        printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
               ifsta->auth_alg);
        ifsta->auth_transaction = -1;
-       ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0;
+       ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
+       ifsta->auth_tries = ifsta->assoc_tries = 0;
        netif_carrier_off(dev);
 }
 
@@ -2970,8 +2084,10 @@ void ieee80211_sta_req_auth(struct net_device *dev,
        if (sdata->type != IEEE80211_IF_TYPE_STA)
                return;
 
-       if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
-           (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+       if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
+                               IEEE80211_STA_AUTO_BSSID_SEL)) &&
+           (ifsta->flags & (IEEE80211_STA_SSID_SET |
+                               IEEE80211_STA_AUTO_SSID_SEL))) {
                set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
                queue_work(local->hw.workqueue, &ifsta->work);
        }
@@ -2985,7 +2101,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
        if (!memcmp(ifsta->ssid, ssid, ssid_len))
                return 1;
 
-       if (ifsta->auto_bssid_sel)
+       if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
                return 0;
 
        hidden_ssid = 1;
@@ -3014,12 +2130,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        struct ieee80211_sta_bss *bss, *selected = NULL;
        int top_rssi = 0, freq;
 
-       rtnl_lock();
-
-       if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
-           !ifsta->auto_ssid_sel) {
+       if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+           IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) {
                ifsta->state = IEEE80211_AUTHENTICATE;
-               rtnl_unlock();
                ieee80211_sta_reset_auth(dev, ifsta);
                return 0;
        }
@@ -3034,14 +2147,15 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                    !!sdata->default_key)
                        continue;
 
-               if (!ifsta->auto_channel_sel && bss->freq != freq)
+               if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
+                   bss->freq != freq)
                        continue;
 
-               if (!ifsta->auto_bssid_sel &&
+               if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) &&
                    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
                        continue;
 
-               if (!ifsta->auto_ssid_sel &&
+               if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) &&
                    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
                        continue;
 
@@ -3056,24 +2170,26 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 
        if (selected) {
                ieee80211_set_channel(local, -1, selected->freq);
-               if (!ifsta->ssid_set)
+               if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
                        ieee80211_sta_set_ssid(dev, selected->ssid,
                                               selected->ssid_len);
                ieee80211_sta_set_bssid(dev, selected->bssid);
                ieee80211_rx_bss_put(dev, selected);
                ifsta->state = IEEE80211_AUTHENTICATE;
-               rtnl_unlock();
                ieee80211_sta_reset_auth(dev, ifsta);
                return 0;
        } else {
                if (ifsta->state != IEEE80211_AUTHENTICATE) {
-                       ieee80211_sta_start_scan(dev, NULL, 0);
+                       if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
+                               ieee80211_sta_start_scan(dev, NULL, 0);
+                       else
+                               ieee80211_sta_start_scan(dev, ifsta->ssid,
+                                                        ifsta->ssid_len);
                        ifsta->state = IEEE80211_AUTHENTICATE;
                        set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
                } else
                        ifsta->state = IEEE80211_DISABLED;
        }
-       rtnl_unlock();
        return -1;
 }
 
@@ -3181,8 +2297,9 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                               "for IBSS beacon\n", dev->name);
                        break;
                }
-               control.tx_rate = (local->short_preamble &&
-                                  (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+               control.tx_rate =
+                       ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
+                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
                        rate->val2 : rate->val;
                control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
                control.power_level = local->hw.conf.power_level;
@@ -3213,8 +2330,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                mode = local->oper_hw_mode;
                for (i = 0; i < bss->supp_rates_len; i++) {
                        int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-                       if (mode->mode == MODE_ATHEROS_TURBO)
-                               bitrate *= 2;
                        for (j = 0; j < mode->num_rates; j++)
                                if (mode->rates[j].rate == bitrate)
                                        rates |= BIT(j);
@@ -3287,8 +2402,6 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        pos = bss->supp_rates;
        for (i = 0; i < mode->num_rates; i++) {
                int rate = mode->rates[i].rate;
-               if (mode->mode == MODE_ATHEROS_TURBO)
-                       rate /= 2;
                *pos++ = (u8) (rate / 5);
        }
 
@@ -3361,10 +2474,10 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 
                if (time_after(jiffies, ifsta->ibss_join_req +
                               IEEE80211_IBSS_JOIN_TIMEOUT)) {
-                       if (ifsta->create_ibss &&
+                       if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
                            local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
                                return ieee80211_sta_create_ibss(dev, ifsta);
-                       if (ifsta->create_ibss) {
+                       if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
                                printk(KERN_DEBUG "%s: IBSS not allowed on the"
                                       " configured channel %d (%d MHz)\n",
                                       dev->name, local->hw.conf.channel,
@@ -3425,13 +2538,17 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
        ifsta = &sdata->u.sta;
 
        if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
-               ifsta->prev_bssid_set = 0;
+               ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
        memcpy(ifsta->ssid, ssid, len);
        memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
        ifsta->ssid_len = len;
 
-       ifsta->ssid_set = len ? 1 : 0;
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
+       if (len)
+               ifsta->flags |= IEEE80211_STA_SSID_SET;
+       else
+               ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+       if (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+           !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
                ifsta->ibss_join_req = jiffies;
                ifsta->state = IEEE80211_IBSS_SEARCH;
                return ieee80211_sta_find_ibss(dev, ifsta);
@@ -3469,10 +2586,11 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
                }
        }
 
-       if (!is_valid_ether_addr(bssid))
-               ifsta->bssid_set = 0;
+       if (is_valid_ether_addr(bssid))
+               ifsta->flags |= IEEE80211_STA_BSSID_SET;
        else
-               ifsta->bssid_set = 1;
+               ifsta->flags &= ~IEEE80211_STA_BSSID_SET;
+
        return 0;
 }
 
@@ -3523,35 +2641,41 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
                printk(KERN_DEBUG "%s: failed to restore operational"
                       "channel after scan\n", dev->name);
 
-       if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
-           ieee80211_if_config(dev))
-               printk(KERN_DEBUG "%s: failed to restore operational"
-                      "BSSID after scan\n", dev->name);
+
+       netif_tx_lock_bh(local->mdev);
+       local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
+       local->ops->configure_filter(local_to_hw(local),
+                                    FIF_BCN_PRBRESP_PROMISC,
+                                    &local->filter_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
+
+       netif_tx_unlock_bh(local->mdev);
 
        memset(&wrqu, 0, sizeof(wrqu));
        wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
                /* No need to wake the master device. */
                if (sdata->dev == local->mdev)
                        continue;
 
                if (sdata->type == IEEE80211_IF_TYPE_STA) {
-                       if (sdata->u.sta.associated)
+                       if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
                                ieee80211_send_nullfunc(local, sdata, 0);
                        ieee80211_sta_timer((unsigned long)sdata);
                }
 
                netif_wake_queue(sdata->dev);
        }
-       read_unlock(&local->sub_if_lock);
+       rcu_read_unlock();
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-               if (!ifsta->bssid_set ||
+               if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
                    (!ifsta->state == IEEE80211_IBSS_JOINED &&
                    !ieee80211_sta_active_ibss(dev)))
                        ieee80211_sta_find_ibss(dev, ifsta);
@@ -3683,8 +2807,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
        local->sta_scanning = 1;
 
-       read_lock(&local->sub_if_lock);
-       list_for_each_entry(sdata, &local->sub_if_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
                /* Don't stop the master interface, otherwise we can't transmit
                 * probes! */
@@ -3693,10 +2817,10 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
                netif_stop_queue(sdata->dev);
                if (sdata->type == IEEE80211_IF_TYPE_STA &&
-                   sdata->u.sta.associated)
+                   (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
                        ieee80211_send_nullfunc(local, sdata, 1);
        }
-       read_unlock(&local->sub_if_lock);
+       rcu_read_unlock();
 
        if (ssid) {
                local->scan_ssid_len = ssid_len;
@@ -3710,10 +2834,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
        local->scan_channel_idx = 0;
        local->scan_dev = dev;
 
-       if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
-           ieee80211_if_config(dev))
-               printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
-                      dev->name);
+       netif_tx_lock_bh(local->mdev);
+       local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
+       local->ops->configure_filter(local_to_hw(local),
+                                    FIF_BCN_PRBRESP_PROMISC,
+                                    &local->filter_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
+       netif_tx_unlock_bh(local->mdev);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
        queue_delayed_work(local->hw.workqueue, &local->scan_work,
@@ -3963,7 +3091,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
        }
 
        printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
-              local->mdev->name, MAC_ARG(addr), dev->name);
+              wiphy_name(local->hw.wiphy), MAC_ARG(addr), dev->name);
 
        sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
        if (!sta)
@@ -4006,7 +3134,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
        if (sdata->type != IEEE80211_IF_TYPE_STA)
                return -EINVAL;
 
-       if (!ifsta->associated)
+       if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
                return -1;
 
        ieee80211_send_disassoc(dev, ifsta, reason);
diff --git a/package/mac80211/src/mac80211/key.c b/package/mac80211/src/mac80211/key.c
new file mode 100644 (file)
index 0000000..d9ab087
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "debugfs_key.h"
+#include "aes_ccm.h"
+
+
+/*
+ * Key handling basics
+ *
+ * Key handling in mac80211 is done based on per-interface (sub_if_data)
+ * keys and per-station keys. Since each station belongs to an interface,
+ * each station key also belongs to that interface.
+ *
+ * Hardware acceleration is done on a best-effort basis, for each key
+ * that is eligible the hardware is asked to enable that key but if
+ * it cannot do that they key is simply kept for software encryption.
+ * There is currently no way of knowing this except by looking into
+ * debugfs.
+ *
+ * All operations here are called under RTNL so no extra locking is
+ * required.
+ */
+
+static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 zero_addr[ETH_ALEN];
+
+static const u8 *get_mac_for_key(struct ieee80211_key *key)
+{
+       const u8 *addr = bcast_addr;
+
+       /*
+        * If we're an AP we won't ever receive frames with a non-WEP
+        * group key so we tell the driver that by using the zero MAC
+        * address to indicate a transmit-only key.
+        */
+       if (key->conf.alg != ALG_WEP &&
+           (key->sdata->type == IEEE80211_IF_TYPE_AP ||
+            key->sdata->type == IEEE80211_IF_TYPE_VLAN))
+               addr = zero_addr;
+
+       if (key->sta)
+               addr = key->sta->addr;
+
+       return addr;
+}
+
+static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
+{
+       const u8 *addr;
+       int ret;
+
+       if (!key->local->ops->set_key)
+               return;
+
+       addr = get_mac_for_key(key);
+
+       ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY,
+                                      key->sdata->dev->dev_addr, addr,
+                                      &key->conf);
+
+       if (!ret)
+               key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+       if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
+               printk(KERN_ERR "mac80211-%s: failed to set key "
+                      "(%d, " MAC_FMT ") to hardware (%d)\n",
+                      wiphy_name(key->local->hw.wiphy),
+                      key->conf.keyidx, MAC_ARG(addr), ret);
+}
+
+static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
+{
+       const u8 *addr;
+       int ret;
+
+       if (!key->local->ops->set_key)
+               return;
+
+       if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+               return;
+
+       addr = get_mac_for_key(key);
+
+       ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY,
+                                      key->sdata->dev->dev_addr, addr,
+                                      &key->conf);
+
+       if (ret)
+               printk(KERN_ERR "mac80211-%s: failed to remove key "
+                      "(%d, " MAC_FMT ") from hardware (%d)\n",
+                      wiphy_name(key->local->hw.wiphy),
+                      key->conf.keyidx, MAC_ARG(addr), ret);
+
+       key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+}
+
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+                                         struct sta_info *sta,
+                                         enum ieee80211_key_alg alg,
+                                         int idx,
+                                         size_t key_len,
+                                         const u8 *key_data)
+{
+       struct ieee80211_key *key;
+
+       BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS);
+
+       key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
+       if (!key)
+               return NULL;
+
+       /*
+        * Default to software encryption; we'll later upload the
+        * key to the hardware if possible.
+        */
+       key->conf.flags = 0;
+       key->flags = 0;
+
+       key->conf.alg = alg;
+       key->conf.keyidx = idx;
+       key->conf.keylen = key_len;
+       memcpy(key->conf.key, key_data, key_len);
+
+       key->local = sdata->local;
+       key->sdata = sdata;
+       key->sta = sta;
+
+       if (alg == ALG_CCMP) {
+               /*
+                * Initialize AES key state here as an optimization so that
+                * it does not need to be initialized for every packet.
+                */
+               key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
+               if (!key->u.ccmp.tfm) {
+                       ieee80211_key_free(key);
+                       return NULL;
+               }
+       }
+
+       ieee80211_debugfs_key_add(key->local, key);
+
+       /* remove key first */
+       if (sta)
+               ieee80211_key_free(sta->key);
+       else
+               ieee80211_key_free(sdata->keys[idx]);
+
+       if (sta) {
+               ieee80211_debugfs_key_sta_link(key, sta);
+
+               /*
+                * some hardware cannot handle TKIP with QoS, so
+                * we indicate whether QoS could be in use.
+                */
+               if (sta->flags & WLAN_STA_WME)
+                       key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
+       } else {
+               if (sdata->type == IEEE80211_IF_TYPE_STA) {
+                       struct sta_info *ap;
+
+                       /* same here, the AP could be using QoS */
+                       ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
+                       if (ap) {
+                               if (ap->flags & WLAN_STA_WME)
+                                       key->conf.flags |=
+                                               IEEE80211_KEY_FLAG_WMM_STA;
+                               sta_info_put(ap);
+                       }
+               }
+       }
+
+       /* enable hwaccel if appropriate */
+       if (netif_running(key->sdata->dev))
+               ieee80211_key_enable_hw_accel(key);
+
+       if (sta)
+               rcu_assign_pointer(sta->key, key);
+       else
+               rcu_assign_pointer(sdata->keys[idx], key);
+
+       list_add(&key->list, &sdata->key_list);
+
+       return key;
+}
+
+void ieee80211_key_free(struct ieee80211_key *key)
+{
+       if (!key)
+               return;
+
+       if (key->sta) {
+               rcu_assign_pointer(key->sta->key, NULL);
+       } else {
+               if (key->sdata->default_key == key)
+                       ieee80211_set_default_key(key->sdata, -1);
+               if (key->conf.keyidx >= 0 &&
+                   key->conf.keyidx < NUM_DEFAULT_KEYS)
+                       rcu_assign_pointer(key->sdata->keys[key->conf.keyidx],
+                                          NULL);
+               else
+                       WARN_ON(1);
+       }
+
+       /* wait for all key users to complete */
+       synchronize_rcu();
+
+       /* remove from hwaccel if appropriate */
+       ieee80211_key_disable_hw_accel(key);
+
+       if (key->conf.alg == ALG_CCMP)
+               ieee80211_aes_key_free(key->u.ccmp.tfm);
+       ieee80211_debugfs_key_remove(key);
+
+       list_del(&key->list);
+
+       kfree(key);
+}
+
+void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
+{
+       struct ieee80211_key *key = NULL;
+
+       if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
+               key = sdata->keys[idx];
+
+       if (sdata->default_key != key) {
+               ieee80211_debugfs_key_remove_default(sdata);
+
+               rcu_assign_pointer(sdata->default_key, key);
+
+               if (sdata->default_key)
+                       ieee80211_debugfs_key_add_default(sdata);
+       }
+}
+
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_key *key, *tmp;
+
+       list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
+               ieee80211_key_free(key);
+}
+
+void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_key *key;
+
+       WARN_ON(!netif_running(sdata->dev));
+       if (!netif_running(sdata->dev))
+               return;
+
+       list_for_each_entry(key, &sdata->key_list, list)
+               ieee80211_key_enable_hw_accel(key);
+}
+
+void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_key *key;
+
+       list_for_each_entry(key, &sdata->key_list, list)
+               ieee80211_key_disable_hw_accel(key);
+}
diff --git a/package/mac80211/src/mac80211/rc80211_lowest.c b/package/mac80211/src/mac80211/rc80211_lowest.c
deleted file mode 100644 (file)
index c11b0d8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- * Copyright (c) 2006-2007 Jiri Benc <jbenc@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/compiler.h>
-
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-#include "ieee80211_rate.h"
-#include "debugfs.h"
-
-static void rate_control_lowest_tx_status(void *priv, struct net_device *dev,
-                                          struct sk_buff *skb,
-                                          struct ieee80211_tx_status *status)
-{
-}
-
-static struct ieee80211_rate *
-rate_control_lowest_get_rate(void *priv, struct net_device *dev,
-                             struct sk_buff *skb,
-                             struct rate_control_extra *extra)
-{
-       struct ieee80211_hw_mode *mode = extra->mode;
-       int i;
-
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-
-               if (rate->flags & IEEE80211_RATE_SUPPORTED)
-                       return rate;
-       }
-       return &mode->rates[0];
-}
-
-static void rate_control_lowest_rate_init(void *priv, void *priv_sta,
-                                          struct ieee80211_local *local,
-                                          struct sta_info *sta)
-{
-       sta->txrate = 0;
-}
-
-static void *rate_control_lowest_alloc(struct ieee80211_local *local)
-{
-       return local;
-}
-
-static void rate_control_lowest_free(void *priv)
-{
-}
-
-static void rate_control_lowest_clear(void *priv)
-{
-}
-
-static void *rate_control_lowest_alloc_sta(void *priv, gfp_t gfp)
-{
-       return priv;
-}
-
-static void rate_control_lowest_free_sta(void *priv, void *priv_sta)
-{
-}
-
-static struct rate_control_ops rate_control_lowest = {
-       .module = THIS_MODULE,
-       .name = "lowest",
-       .tx_status = rate_control_lowest_tx_status,
-       .get_rate = rate_control_lowest_get_rate,
-       .rate_init = rate_control_lowest_rate_init,
-       .clear = rate_control_lowest_clear,
-       .alloc = rate_control_lowest_alloc,
-       .free = rate_control_lowest_free,
-       .alloc_sta = rate_control_lowest_alloc_sta,
-       .free_sta = rate_control_lowest_free_sta,
-};
-
-static int __init rate_control_lowest_init(void)
-{
-       return ieee80211_rate_control_register(&rate_control_lowest);
-}
-
-
-static void __exit rate_control_lowest_exit(void)
-{
-       ieee80211_rate_control_unregister(&rate_control_lowest);
-}
-
-
-module_init(rate_control_lowest_init);
-module_exit(rate_control_lowest_exit);
-
-MODULE_DESCRIPTION("Forced 1 mbps rate control module for mac80211");
-MODULE_LICENSE("GPL");
-
index 5ae7fc45466547cddb6009abe8f04162f4c0287c..ef91ce428acaafaede5a9d0fd6f3609984152c59 100644 (file)
@@ -147,14 +147,6 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
        srctrl = sta->rate_ctrl_priv;
        srctrl->tx_num_xmit++;
        if (status->excessive_retries) {
-               sta->antenna_sel_tx = sta->antenna_sel_tx == 1 ? 2 : 1;
-               sta->antenna_sel_rx = sta->antenna_sel_rx == 1 ? 2 : 1;
-               if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) {
-                       printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d "
-                              "RX antenna --> %d (@%lu)\n",
-                              dev->name, MAC_ARG(hdr->addr1),
-                              sta->antenna_sel_tx, sta->antenna_sel_rx, jiffies);
-               }
                srctrl->tx_num_failures++;
                sta->tx_retry_failed++;
                sta->tx_num_consecutive_failures++;
@@ -187,9 +179,13 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
                }
 #endif
 
-               if (per_failed > local->rate_ctrl_num_down) {
+               /*
+                * XXX: Make these configurable once we have an
+                * interface to the rate control algorithms
+                */
+               if (per_failed > RATE_CONTROL_NUM_DOWN) {
                        rate_control_rate_dec(local, sta);
-               } else if (per_failed < local->rate_ctrl_num_up) {
+               } else if (per_failed < RATE_CONTROL_NUM_UP) {
                        rate_control_rate_inc(local, sta);
                }
                srctrl->tx_avg_rate_sum += status->control.rate->rate;
@@ -427,7 +423,7 @@ static void __exit rate_control_simple_exit(void)
 }
 
 
-module_init(rate_control_simple_init);
+subsys_initcall(rate_control_simple_init);
 module_exit(rate_control_simple_exit);
 
 MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
index 32e5dca6b6b96be76690a9d5fd0961e2c68d9f23..f42678fa62d1ec6711f0ef666a3859a366110884 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <net/mac80211.h>
+#include "ieee80211_i.h"
 
 static int ieee80211_regdom = 0x10; /* FCC */
 module_param(ieee80211_regdom, int, 0444);
@@ -81,12 +82,6 @@ static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
 
        chan->flag = 0;
 
-       if (ieee80211_regdom == 64 &&
-           (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
-               /* Do not allow Turbo modes in Japan. */
-               return;
-       }
-
        for (i = 0; channel_range[i].start_freq; i++) {
                const struct ieee80211_channel_range *r = &channel_range[i];
                if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
diff --git a/package/mac80211/src/mac80211/rx.c b/package/mac80211/src/mac80211/rx.c
new file mode 100644 (file)
index 0000000..064924c
--- /dev/null
@@ -0,0 +1,1579 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rcupdate.h>
+#include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
+
+#include "ieee80211_i.h"
+#include "ieee80211_led.h"
+#include "wep.h"
+#include "wpa.h"
+#include "tkip.h"
+#include "wme.h"
+
+/*
+ * monitor mode reception
+ *
+ * This function cleans up the SKB, i.e. it removes all the stuff
+ * only useful for monitoring.
+ */
+static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
+                                          struct sk_buff *skb,
+                                          int rtap_len)
+{
+       skb_pull(skb, rtap_len);
+
+       if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
+               if (likely(skb->len > FCS_LEN))
+                       skb_trim(skb, skb->len - FCS_LEN);
+               else {
+                       /* driver bug */
+                       WARN_ON(1);
+                       dev_kfree_skb(skb);
+                       skb = NULL;
+               }
+       }
+
+       return skb;
+}
+
+static inline int should_drop_frame(struct ieee80211_rx_status *status,
+                                   struct sk_buff *skb,
+                                   int present_fcs_len,
+                                   int radiotap_len)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+       if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+               return 1;
+       if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len))
+               return 1;
+       if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
+                       cpu_to_le16(IEEE80211_FTYPE_CTL))
+               return 1;
+       return 0;
+}
+
+/*
+ * This function copies a received frame to all monitor interfaces and
+ * returns a cleaned-up SKB that no longer includes the FCS nor the
+ * radiotap header the driver might have added.
+ */
+static struct sk_buff *
+ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
+                    struct ieee80211_rx_status *status)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_rate *rate;
+       int needed_headroom = 0;
+       struct ieee80211_rtap_hdr {
+               struct ieee80211_radiotap_header hdr;
+               u8 flags;
+               u8 rate;
+               __le16 chan_freq;
+               __le16 chan_flags;
+               u8 antsignal;
+               u8 padding_for_rxflags;
+               __le16 rx_flags;
+       } __attribute__ ((packed)) *rthdr;
+       struct sk_buff *skb, *skb2;
+       struct net_device *prev_dev = NULL;
+       int present_fcs_len = 0;
+       int rtap_len = 0;
+
+       /*
+        * First, we may need to make a copy of the skb because
+        *  (1) we need to modify it for radiotap (if not present), and
+        *  (2) the other RX handlers will modify the skb we got.
+        *
+        * We don't need to, of course, if we aren't going to return
+        * the SKB because it has a bad FCS/PLCP checksum.
+        */
+       if (status->flag & RX_FLAG_RADIOTAP)
+               rtap_len = ieee80211_get_radiotap_len(origskb->data);
+       else
+               needed_headroom = sizeof(*rthdr);
+
+       if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+               present_fcs_len = FCS_LEN;
+
+       if (!local->monitors) {
+               if (should_drop_frame(status, origskb, present_fcs_len,
+                                     rtap_len)) {
+                       dev_kfree_skb(origskb);
+                       return NULL;
+               }
+
+               return remove_monitor_info(local, origskb, rtap_len);
+       }
+
+       if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {
+               /* only need to expand headroom if necessary */
+               skb = origskb;
+               origskb = NULL;
+
+               /*
+                * This shouldn't trigger often because most devices have an
+                * RX header they pull before we get here, and that should
+                * be big enough for our radiotap information. We should
+                * probably export the length to drivers so that we can have
+                * them allocate enough headroom to start with.
+                */
+               if (skb_headroom(skb) < needed_headroom &&
+                   pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+                       dev_kfree_skb(skb);
+                       return NULL;
+               }
+       } else {
+               /*
+                * Need to make a copy and possibly remove radiotap header
+                * and FCS from the original.
+                */
+               skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);
+
+               origskb = remove_monitor_info(local, origskb, rtap_len);
+
+               if (!skb)
+                       return origskb;
+       }
+
+       /* if necessary, prepend radiotap information */
+       if (!(status->flag & RX_FLAG_RADIOTAP)) {
+               rthdr = (void *) skb_push(skb, sizeof(*rthdr));
+               memset(rthdr, 0, sizeof(*rthdr));
+               rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+               rthdr->hdr.it_present =
+                       cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+                                   (1 << IEEE80211_RADIOTAP_RATE) |
+                                   (1 << IEEE80211_RADIOTAP_CHANNEL) |
+                                   (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
+                                   (1 << IEEE80211_RADIOTAP_RX_FLAGS));
+               rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
+                              IEEE80211_RADIOTAP_F_FCS : 0;
+
+               /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
+               rthdr->rx_flags = 0;
+               if (status->flag &
+                   (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+                       rthdr->rx_flags |=
+                               cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+
+               rate = ieee80211_get_rate(local, status->phymode,
+                                         status->rate);
+               if (rate)
+                       rthdr->rate = rate->rate / 5;
+
+               rthdr->chan_freq = cpu_to_le16(status->freq);
+
+               if (status->phymode == MODE_IEEE80211A)
+                       rthdr->chan_flags =
+                               cpu_to_le16(IEEE80211_CHAN_OFDM |
+                                           IEEE80211_CHAN_5GHZ);
+               else
+                       rthdr->chan_flags =
+                               cpu_to_le16(IEEE80211_CHAN_DYN |
+                                           IEEE80211_CHAN_2GHZ);
+
+               rthdr->antsignal = status->ssi;
+       }
+
+       skb_set_mac_header(skb, 0);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_802_2);
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!netif_running(sdata->dev))
+                       continue;
+
+               if (sdata->type != IEEE80211_IF_TYPE_MNTR)
+                       continue;
+
+               if (prev_dev) {
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2) {
+                               skb2->dev = prev_dev;
+                               netif_rx(skb2);
+                       }
+               }
+
+               prev_dev = sdata->dev;
+               sdata->dev->stats.rx_packets++;
+               sdata->dev->stats.rx_bytes += skb->len;
+       }
+
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+       } else
+               dev_kfree_skb(skb);
+
+       return origskb;
+}
+
+
+/* pre-rx handlers
+ *
+ * these don't have dev/sdata fields in the rx data
+ * The sta value should also not be used because it may
+ * be NULL even though a STA (in IBSS mode) will be added.
+ */
+
+static ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+{
+       u8 *data = rx->skb->data;
+       int tid;
+
+       /* does the frame have a qos control field? */
+       if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
+               u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
+               /* frame has qos control */
+               tid = qc[0] & QOS_CONTROL_TID_MASK;
+       } else {
+               if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
+                       /* Separate TID for management frames */
+                       tid = NUM_RX_DATA_QUEUES - 1;
+               } else {
+                       /* no qos control present */
+                       tid = 0; /* 802.1d - Best Effort */
+               }
+       }
+
+       I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
+       /* only a debug counter, sta might not be assigned properly yet */
+       if (rx->sta)
+               I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
+
+       rx->u.rx.queue = tid;
+       /* Set skb->priority to 1d tag if highest order bit of TID is not set.
+        * For now, set skb->priority to 0 for other cases. */
+       rx->skb->priority = (tid > 7) ? 0 : tid;
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u32 load = 0, hdrtime;
+       struct ieee80211_rate *rate;
+       struct ieee80211_hw_mode *mode = local->hw.conf.mode;
+       int i;
+
+       /* Estimate total channel use caused by this frame */
+
+       if (unlikely(mode->num_rates < 0))
+               return TXRX_CONTINUE;
+
+       rate = &mode->rates[0];
+       for (i = 0; i < mode->num_rates; i++) {
+               if (mode->rates[i].val == rx->u.rx.status->rate) {
+                       rate = &mode->rates[i];
+                       break;
+               }
+       }
+
+       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+       if (mode->mode == MODE_IEEE80211A ||
+           (mode->mode == MODE_IEEE80211G &&
+            rate->flags & IEEE80211_RATE_ERP))
+               hdrtime = CHAN_UTIL_HDR_SHORT;
+       else
+               hdrtime = CHAN_UTIL_HDR_LONG;
+
+       load = hdrtime;
+       if (!is_multicast_ether_addr(hdr->addr1))
+               load += hdrtime;
+
+       load += skb->len * rate->rate_inv;
+
+       /* Divide channel_use by 8 to avoid wrapping around the counter */
+       load >>= CHAN_UTIL_SHIFT;
+       local->channel_use_raw += load;
+       rx->u.rx.load = load;
+
+       return TXRX_CONTINUE;
+}
+
+ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
+{
+       ieee80211_rx_h_parse_qos,
+       ieee80211_rx_h_load_stats,
+       NULL
+};
+
+/* rx handlers */
+
+static ieee80211_txrx_result
+ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+{
+       if (rx->sta)
+               rx->sta->channel_use_raw += rx->u.rx.load;
+       rx->sdata->channel_use_raw += rx->u.rx.load;
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct sk_buff *skb = rx->skb;
+
+       if (unlikely(local->sta_scanning != 0)) {
+               ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+               return TXRX_QUEUED;
+       }
+
+       if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
+               /* scanning finished during invoking of handlers */
+               I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+               return TXRX_DROP;
+       }
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_hdr *hdr;
+       hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
+       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+               if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
+                            rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+                            hdr->seq_ctrl)) {
+                       if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) {
+                               rx->local->dot11FrameDuplicateCount++;
+                               rx->sta->num_duplicates++;
+                       }
+                       return TXRX_DROP;
+               } else
+                       rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+       }
+
+       if (unlikely(rx->skb->len < 16)) {
+               I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
+               return TXRX_DROP;
+       }
+
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               rx->skb->pkt_type = PACKET_OTHERHOST;
+       else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
+               rx->skb->pkt_type = PACKET_HOST;
+       else if (is_multicast_ether_addr(hdr->addr1)) {
+               if (is_broadcast_ether_addr(hdr->addr1))
+                       rx->skb->pkt_type = PACKET_BROADCAST;
+               else
+                       rx->skb->pkt_type = PACKET_MULTICAST;
+       } else
+               rx->skb->pkt_type = PACKET_OTHERHOST;
+
+       /* Drop disallowed frame classes based on STA auth/assoc state;
+        * IEEE 802.11, Chap 5.5.
+        *
+        * 80211.o does filtering only based on association state, i.e., it
+        * drops Class 3 frames from not associated stations. hostapd sends
+        * deauth/disassoc frames when needed. In addition, hostapd is
+        * responsible for filtering on both auth and assoc states.
+        */
+       if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
+                     ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
+                      (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
+                    rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+                    (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+               if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
+                    !(rx->fc & IEEE80211_FCTL_TODS) &&
+                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+                   || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+                       /* Drop IBSS frames and frames for other hosts
+                        * silently. */
+                       return TXRX_DROP;
+               }
+
+               return TXRX_DROP;
+       }
+
+       return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+       int keyidx;
+       int hdrlen;
+       ieee80211_txrx_result result = TXRX_DROP;
+       struct ieee80211_key *stakey = NULL;
+
+       /*
+        * Key selection 101
+        *
+        * There are three types of keys:
+        *  - GTK (group keys)
+        *  - PTK (pairwise keys)
+        *  - STK (station-to-station pairwise keys)
+        *
+        * When selecting a key, we have to distinguish between multicast
+        * (including broadcast) and unicast frames, the latter can only
+        * use PTKs and STKs while the former always use GTKs. Unless, of
+        * course, actual WEP keys ("pre-RSNA") are used, then unicast
+        * frames can also use key indizes like GTKs. Hence, if we don't
+        * have a PTK/STK we check the key index for a WEP key.
+        *
+        * Note that in a regular BSS, multicast frames are sent by the
+        * AP only, associated stations unicast the frame to the AP first
+        * which then multicasts it on their behalf.
+        *
+        * There is also a slight problem in IBSS mode: GTKs are negotiated
+        * with each station, that is something we don't currently handle.
+        * The spec seems to expect that one negotiates the same key with
+        * every station but there's no such requirement; VLANs could be
+        * possible.
+        */
+
+       if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
+               return TXRX_CONTINUE;
+
+       /*
+        * No point in finding a key and decrypting if the frame is neither
+        * addressed to us nor a multicast frame.
+        */
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return TXRX_CONTINUE;
+
+       if (rx->sta)
+               stakey = rcu_dereference(rx->sta->key);
+
+       if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
+               rx->key = stakey;
+       } else {
+               /*
+                * The device doesn't give us the IV so we won't be
+                * able to look up the key. That's ok though, we
+                * don't need to decrypt the frame, we just won't
+                * be able to keep statistics accurate.
+                * Except for key threshold notifications, should
+                * we somehow allow the driver to tell us which key
+                * the hardware used if this flag is set?
+                */
+               if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+                   (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
+                       return TXRX_CONTINUE;
+
+               hdrlen = ieee80211_get_hdrlen(rx->fc);
+
+               if (rx->skb->len < 8 + hdrlen)
+                       return TXRX_DROP; /* TODO: count this? */
+
+               /*
+                * no need to call ieee80211_wep_get_keyidx,
+                * it verifies a bunch of things we've done already
+                */
+               keyidx = rx->skb->data[hdrlen + 3] >> 6;
+
+               rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+
+               /*
+                * RSNA-protected unicast frames should always be sent with
+                * pairwise or station-to-station keys, but for WEP we allow
+                * using a key index as well.
+                */
+               if (rx->key && rx->key->conf.alg != ALG_WEP &&
+                   !is_multicast_ether_addr(hdr->addr1))
+                       rx->key = NULL;
+       }
+
+       if (rx->key) {
+               rx->key->tx_rx_count++;
+               /* TODO: add threshold stuff again */
+       } else {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: RX protected frame,"
+                              " but have no key\n", rx->dev->name);
+               return TXRX_DROP;
+       }
+
+       /* Check for weak IVs if possible */
+       if (rx->sta && rx->key->conf.alg == ALG_WEP &&
+           ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+           (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
+            !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&
+           ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+               rx->sta->wep_weak_iv_count++;
+
+       switch (rx->key->conf.alg) {
+       case ALG_WEP:
+               result = ieee80211_crypto_wep_decrypt(rx);
+               break;
+       case ALG_TKIP:
+               result = ieee80211_crypto_tkip_decrypt(rx);
+               break;
+       case ALG_CCMP:
+               result = ieee80211_crypto_ccmp_decrypt(rx);
+               break;
+       }
+
+       /* either the frame has been decrypted or will be dropped */
+       rx->u.rx.status->flag |= RX_FLAG_DECRYPTED;
+
+       return result;
+}
+
+static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata;
+       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+       if (sdata->bss)
+               atomic_inc(&sdata->bss->num_sta_ps);
+       sta->flags |= WLAN_STA_PS;
+       sta->pspoll = 0;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
+              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+}
+
+static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sk_buff *skb;
+       int sent = 0;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_tx_packet_data *pkt_data;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+       if (sdata->bss)
+               atomic_dec(&sdata->bss->num_sta_ps);
+       sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
+       sta->pspoll = 0;
+       if (!skb_queue_empty(&sta->ps_tx_buf)) {
+               if (local->ops->set_tim)
+                       local->ops->set_tim(local_to_hw(local), sta->aid, 0);
+               if (sdata->bss)
+                       bss_tim_clear(local, sdata->bss, sta->aid);
+       }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
+              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+       /* Send all buffered frames to the station */
+       while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+               sent++;
+               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+               dev_queue_xmit(skb);
+       }
+       while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+               local->total_ps_buffered--;
+               sent++;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+               printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+                      "since STA not sleeping anymore\n", dev->name,
+                      MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+               dev_queue_xmit(skb);
+       }
+
+       return sent;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+{
+       struct sta_info *sta = rx->sta;
+       struct net_device *dev = rx->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+       if (!sta)
+               return TXRX_CONTINUE;
+
+       /* Update last_rx only for IBSS packets which are for the current
+        * BSSID to avoid keeping the current IBSS network alive in cases where
+        * other STAs are using different BSSID. */
+       if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
+               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
+               if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+                       sta->last_rx = jiffies;
+       } else
+       if (!is_multicast_ether_addr(hdr->addr1) ||
+           rx->sdata->type == IEEE80211_IF_TYPE_STA) {
+               /* Update last_rx only for unicast frames in order to prevent
+                * the Probe Request frames (the only broadcast frames from a
+                * STA in infrastructure mode) from keeping a connection alive.
+                */
+               sta->last_rx = jiffies;
+       }
+
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return TXRX_CONTINUE;
+
+       sta->rx_fragments++;
+       sta->rx_bytes += rx->skb->len;
+       sta->last_rssi = rx->u.rx.status->ssi;
+       sta->last_signal = rx->u.rx.status->signal;
+       sta->last_noise = rx->u.rx.status->noise;
+
+       if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
+               /* Change STA power saving mode only in the end of a frame
+                * exchange sequence */
+               if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+                       rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+               else if (!(sta->flags & WLAN_STA_PS) &&
+                        (rx->fc & IEEE80211_FCTL_PM))
+                       ap_sta_ps_start(dev, sta);
+       }
+
+       /* Drop data::nullfunc frames silently, since they are used only to
+        * control station power saving mode. */
+       if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+           (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) {
+               I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
+               /* Update counter and free packet here to avoid counting this
+                * as a dropped packed. */
+               sta->rx_packets++;
+               dev_kfree_skb(rx->skb);
+               return TXRX_QUEUED;
+       }
+
+       return TXRX_CONTINUE;
+} /* ieee80211_rx_h_sta_process */
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
+                        unsigned int frag, unsigned int seq, int rx_queue,
+                        struct sk_buff **skb)
+{
+       struct ieee80211_fragment_entry *entry;
+       int idx;
+
+       idx = sdata->fragment_next;
+       entry = &sdata->fragments[sdata->fragment_next++];
+       if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
+               sdata->fragment_next = 0;
+
+       if (!skb_queue_empty(&entry->skb_list)) {
+#ifdef CONFIG_MAC80211_DEBUG
+               struct ieee80211_hdr *hdr =
+                       (struct ieee80211_hdr *) entry->skb_list.next->data;
+               printk(KERN_DEBUG "%s: RX reassembly removed oldest "
+                      "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
+                      "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
+                      sdata->dev->name, idx,
+                      jiffies - entry->first_frag_time, entry->seq,
+                      entry->last_frag, MAC_ARG(hdr->addr1),
+                      MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+               __skb_queue_purge(&entry->skb_list);
+       }
+
+       __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
+       *skb = NULL;
+       entry->first_frag_time = jiffies;
+       entry->seq = seq;
+       entry->rx_queue = rx_queue;
+       entry->last_frag = frag;
+       entry->ccmp = 0;
+       entry->extra_len = 0;
+
+       return entry;
+}
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
+                         u16 fc, unsigned int frag, unsigned int seq,
+                         int rx_queue, struct ieee80211_hdr *hdr)
+{
+       struct ieee80211_fragment_entry *entry;
+       int i, idx;
+
+       idx = sdata->fragment_next;
+       for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+               struct ieee80211_hdr *f_hdr;
+               u16 f_fc;
+
+               idx--;
+               if (idx < 0)
+                       idx = IEEE80211_FRAGMENT_MAX - 1;
+
+               entry = &sdata->fragments[idx];
+               if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
+                   entry->rx_queue != rx_queue ||
+                   entry->last_frag + 1 != frag)
+                       continue;
+
+               f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
+               f_fc = le16_to_cpu(f_hdr->frame_control);
+
+               if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) ||
+                   compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
+                   compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
+                       continue;
+
+               if (entry->first_frag_time + 2 * HZ < jiffies) {
+                       __skb_queue_purge(&entry->skb_list);
+                       continue;
+               }
+               return entry;
+       }
+
+       return NULL;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_hdr *hdr;
+       u16 sc;
+       unsigned int frag, seq;
+       struct ieee80211_fragment_entry *entry;
+       struct sk_buff *skb;
+
+       hdr = (struct ieee80211_hdr *) rx->skb->data;
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       frag = sc & IEEE80211_SCTL_FRAG;
+
+       if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) ||
+                  (rx->skb)->len < 24 ||
+                  is_multicast_ether_addr(hdr->addr1))) {
+               /* not fragmented */
+               goto out;
+       }
+       I802_DEBUG_INC(rx->local->rx_handlers_fragments);
+
+       seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+
+       if (frag == 0) {
+               /* This is the first fragment of a new frame. */
+               entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
+                                                rx->u.rx.queue, &(rx->skb));
+               if (rx->key && rx->key->conf.alg == ALG_CCMP &&
+                   (rx->fc & IEEE80211_FCTL_PROTECTED)) {
+                       /* Store CCMP PN so that we can verify that the next
+                        * fragment has a sequential PN value. */
+                       entry->ccmp = 1;
+                       memcpy(entry->last_pn,
+                              rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+                              CCMP_PN_LEN);
+               }
+               return TXRX_QUEUED;
+       }
+
+       /* This is a fragment for a frame that should already be pending in
+        * fragment cache. Add this fragment to the end of the pending entry.
+        */
+       entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
+                                         rx->u.rx.queue, hdr);
+       if (!entry) {
+               I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+               return TXRX_DROP;
+       }
+
+       /* Verify that MPDUs within one MSDU have sequential PN values.
+        * (IEEE 802.11i, 8.3.3.4.5) */
+       if (entry->ccmp) {
+               int i;
+               u8 pn[CCMP_PN_LEN], *rpn;
+               if (!rx->key || rx->key->conf.alg != ALG_CCMP)
+                       return TXRX_DROP;
+               memcpy(pn, entry->last_pn, CCMP_PN_LEN);
+               for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
+                       pn[i]++;
+                       if (pn[i])
+                               break;
+               }
+               rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+               if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: defrag: CCMP PN not "
+                                      "sequential A2=" MAC_FMT
+                                      " PN=%02x%02x%02x%02x%02x%02x "
+                                      "(expected %02x%02x%02x%02x%02x%02x)\n",
+                                      rx->dev->name, MAC_ARG(hdr->addr2),
+                                      rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
+                                      rpn[5], pn[0], pn[1], pn[2], pn[3],
+                                      pn[4], pn[5]);
+                       return TXRX_DROP;
+               }
+               memcpy(entry->last_pn, pn, CCMP_PN_LEN);
+       }
+
+       skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
+       __skb_queue_tail(&entry->skb_list, rx->skb);
+       entry->last_frag = frag;
+       entry->extra_len += rx->skb->len;
+       if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
+               rx->skb = NULL;
+               return TXRX_QUEUED;
+       }
+
+       rx->skb = __skb_dequeue(&entry->skb_list);
+       if (skb_tailroom(rx->skb) < entry->extra_len) {
+               I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
+               if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
+                                             GFP_ATOMIC))) {
+                       I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+                       __skb_queue_purge(&entry->skb_list);
+                       return TXRX_DROP;
+               }
+       }
+       while ((skb = __skb_dequeue(&entry->skb_list))) {
+               memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len);
+               dev_kfree_skb(skb);
+       }
+
+       /* Complete frame has been reassembled - process it now */
+       rx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+
+ out:
+       if (rx->sta)
+               rx->sta->rx_packets++;
+       if (is_multicast_ether_addr(hdr->addr1))
+               rx->local->dot11MulticastReceivedFrameCount++;
+       else
+               ieee80211_led_rx(rx->local);
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+{
+       struct sk_buff *skb;
+       int no_pending_pkts;
+
+       if (likely(!rx->sta ||
+                  (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
+                  (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
+                  !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
+               return TXRX_CONTINUE;
+
+       skb = skb_dequeue(&rx->sta->tx_filtered);
+       if (!skb) {
+               skb = skb_dequeue(&rx->sta->ps_tx_buf);
+               if (skb)
+                       rx->local->total_ps_buffered--;
+       }
+       no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
+               skb_queue_empty(&rx->sta->ps_tx_buf);
+
+       if (skb) {
+               struct ieee80211_hdr *hdr =
+                       (struct ieee80211_hdr *) skb->data;
+
+               /* tell TX path to send one frame even though the STA may
+                * still remain is PS mode after this frame exchange */
+               rx->sta->pspoll = 1;
+
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+               printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
+                      "after %d)\n",
+                      MAC_ARG(rx->sta->addr), rx->sta->aid,
+                      skb_queue_len(&rx->sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+               /* Use MoreData flag to indicate whether there are more
+                * buffered frames for this STA */
+               if (no_pending_pkts) {
+                       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+                       rx->sta->flags &= ~WLAN_STA_TIM;
+               } else
+                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+               dev_queue_xmit(skb);
+
+               if (no_pending_pkts) {
+                       if (rx->local->ops->set_tim)
+                               rx->local->ops->set_tim(local_to_hw(rx->local),
+                                                      rx->sta->aid, 0);
+                       if (rx->sdata->bss)
+                               bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
+               }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+       } else if (!rx->u.rx.sent_ps_buffered) {
+               printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
+                      "though there is no buffered frames for it\n",
+                      rx->dev->name, MAC_ARG(rx->sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+       }
+
+       /* Free PS Poll skb here instead of returning TXRX_DROP that would
+        * count as an dropped frame. */
+       dev_kfree_skb(rx->skb);
+
+       return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+{
+       u16 fc = rx->fc;
+       u8 *data = rx->skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
+
+       if (!WLAN_FC_IS_QOS_DATA(fc))
+               return TXRX_CONTINUE;
+
+       /* remove the qos control field, update frame type and meta-data */
+       memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
+       hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
+       /* change frame type to non QOS */
+       rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
+       hdr->frame_control = cpu_to_le16(fc);
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+{
+       if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
+           rx->sdata->type != IEEE80211_IF_TYPE_STA &&
+           (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return TXRX_CONTINUE;
+
+       if (unlikely(rx->sdata->ieee802_1x &&
+                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+                    (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+                    (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
+                    !ieee80211_is_eapol(rx->skb))) {
+#ifdef CONFIG_MAC80211_DEBUG
+               struct ieee80211_hdr *hdr =
+                       (struct ieee80211_hdr *) rx->skb->data;
+               printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
+                      " (unauthorized port)\n", rx->dev->name,
+                      MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+               return TXRX_DROP;
+       }
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+{
+       /*
+        * Pass through unencrypted frames if the hardware has
+        * decrypted them already.
+        */
+       if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
+               return TXRX_CONTINUE;
+
+       /* Drop unencrypted frames if key is set. */
+       if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
+                    (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+                    (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+                    rx->sdata->drop_unencrypted &&
+                    (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
+                              "encryption\n", rx->dev->name);
+               return TXRX_DROP;
+       }
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+{
+       struct net_device *dev = rx->dev;
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+       u16 fc, hdrlen, ethertype;
+       u8 *payload;
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       struct sk_buff *skb = rx->skb, *skb2;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return TXRX_CONTINUE;
+
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return TXRX_DROP;
+
+       hdrlen = ieee80211_get_hdrlen(fc);
+
+       /* convert IEEE 802.11 header + possible LLC headers into Ethernet
+        * header
+        * IEEE 802.11 address fields:
+        * ToDS FromDS Addr1 Addr2 Addr3 Addr4
+        *   0     0   DA    SA    BSSID n/a
+        *   0     1   DA    BSSID SA    n/a
+        *   1     0   BSSID SA    DA    n/a
+        *   1     1   RA    TA    DA    SA
+        */
+
+       switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+       case IEEE80211_FCTL_TODS:
+               /* BSSID SA DA */
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+
+               if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
+                            sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: dropped ToDS frame "
+                                      "(BSSID=" MAC_FMT
+                                      " SA=" MAC_FMT
+                                      " DA=" MAC_FMT ")\n",
+                                      dev->name,
+                                      MAC_ARG(hdr->addr1),
+                                      MAC_ARG(hdr->addr2),
+                                      MAC_ARG(hdr->addr3));
+                       return TXRX_DROP;
+               }
+               break;
+       case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+               /* RA TA DA SA */
+               memcpy(dst, hdr->addr3, ETH_ALEN);
+               memcpy(src, hdr->addr4, ETH_ALEN);
+
+               if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
+                                      "frame (RA=" MAC_FMT
+                                      " TA=" MAC_FMT " DA=" MAC_FMT
+                                      " SA=" MAC_FMT ")\n",
+                                      rx->dev->name,
+                                      MAC_ARG(hdr->addr1),
+                                      MAC_ARG(hdr->addr2),
+                                      MAC_ARG(hdr->addr3),
+                                      MAC_ARG(hdr->addr4));
+                       return TXRX_DROP;
+               }
+               break;
+       case IEEE80211_FCTL_FROMDS:
+               /* DA BSSID SA */
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr3, ETH_ALEN);
+
+               if (sdata->type != IEEE80211_IF_TYPE_STA ||
+                   (is_multicast_ether_addr(dst) &&
+                    !compare_ether_addr(src, dev->dev_addr)))
+                       return TXRX_DROP;
+               break;
+       case 0:
+               /* DA SA BSSID */
+               memcpy(dst, hdr->addr1, ETH_ALEN);
+               memcpy(src, hdr->addr2, ETH_ALEN);
+
+               if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+                       if (net_ratelimit()) {
+                               printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
+                                      MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
+                                      ")\n",
+                                      dev->name, MAC_ARG(hdr->addr1),
+                                      MAC_ARG(hdr->addr2),
+                                      MAC_ARG(hdr->addr3));
+                       }
+                       return TXRX_DROP;
+               }
+               break;
+       }
+
+       payload = skb->data + hdrlen;
+
+       if (unlikely(skb->len - hdrlen < 8)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: RX too short data frame "
+                              "payload\n", dev->name);
+               }
+               return TXRX_DROP;
+       }
+
+       ethertype = (payload[6] << 8) | payload[7];
+
+       if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+                   ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+                  compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
+               /* remove RFC1042 or Bridge-Tunnel encapsulation and
+                * replace EtherType */
+               skb_pull(skb, hdrlen + 6);
+               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+       } else {
+               struct ethhdr *ehdr;
+               __be16 len;
+               skb_pull(skb, hdrlen);
+               len = htons(skb->len);
+               ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
+               memcpy(ehdr->h_dest, dst, ETH_ALEN);
+               memcpy(ehdr->h_source, src, ETH_ALEN);
+               ehdr->h_proto = len;
+       }
+       skb->dev = dev;
+
+       skb2 = NULL;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+
+       if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
+           || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+           (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+               if (is_multicast_ether_addr(skb->data)) {
+                       /* send multicast frames both to higher layers in
+                        * local net stack and back to the wireless media */
+                       skb2 = skb_copy(skb, GFP_ATOMIC);
+                       if (!skb2 && net_ratelimit())
+                               printk(KERN_DEBUG "%s: failed to clone "
+                                      "multicast frame\n", dev->name);
+               } else {
+                       struct sta_info *dsta;
+                       dsta = sta_info_get(local, skb->data);
+                       if (dsta && !dsta->dev) {
+                               if (net_ratelimit())
+                                       printk(KERN_DEBUG "Station with null "
+                                              "dev structure!\n");
+                       } else if (dsta && dsta->dev == dev) {
+                               /* Destination station is associated to this
+                                * AP, so send the frame directly to it and
+                                * do not pass the frame to local net stack.
+                                */
+                               skb2 = skb;
+                               skb = NULL;
+                       }
+                       if (dsta)
+                               sta_info_put(dsta);
+               }
+       }
+
+       if (skb) {
+               /* deliver to local stack */
+               skb->protocol = eth_type_trans(skb, dev);
+               memset(skb->cb, 0, sizeof(skb->cb));
+               netif_rx(skb);
+       }
+
+       if (skb2) {
+               /* send to wireless media */
+               skb2->protocol = __constant_htons(ETH_P_802_3);
+               skb_set_network_header(skb2, 0);
+               skb_set_mac_header(skb2, 0);
+               dev_queue_xmit(skb2);
+       }
+
+       return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return TXRX_DROP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       if ((sdata->type == IEEE80211_IF_TYPE_STA ||
+            sdata->type == IEEE80211_IF_TYPE_IBSS) &&
+           !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+               ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+       else
+               return TXRX_DROP;
+
+       return TXRX_QUEUED;
+}
+
+static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
+                               struct ieee80211_local *local,
+                               ieee80211_rx_handler *handlers,
+                               struct ieee80211_txrx_data *rx,
+                               struct sta_info *sta)
+{
+       ieee80211_rx_handler *handler;
+       ieee80211_txrx_result res = TXRX_DROP;
+
+       for (handler = handlers; *handler != NULL; handler++) {
+               res = (*handler)(rx);
+
+               switch (res) {
+               case TXRX_CONTINUE:
+                       continue;
+               case TXRX_DROP:
+                       I802_DEBUG_INC(local->rx_handlers_drop);
+                       if (sta)
+                               sta->rx_dropped++;
+                       break;
+               case TXRX_QUEUED:
+                       I802_DEBUG_INC(local->rx_handlers_queued);
+                       break;
+               }
+               break;
+       }
+
+       if (res == TXRX_DROP)
+               dev_kfree_skb(rx->skb);
+       return res;
+}
+
+static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
+                                               ieee80211_rx_handler *handlers,
+                                               struct ieee80211_txrx_data *rx,
+                                               struct sta_info *sta)
+{
+       if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
+           TXRX_CONTINUE)
+               dev_kfree_skb(rx->skb);
+}
+
+static void ieee80211_rx_michael_mic_report(struct net_device *dev,
+                                           struct ieee80211_hdr *hdr,
+                                           struct sta_info *sta,
+                                           struct ieee80211_txrx_data *rx)
+{
+       int keyidx, hdrlen;
+
+       hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
+       if (rx->skb->len >= hdrlen + 4)
+               keyidx = rx->skb->data[hdrlen + 3] >> 6;
+       else
+               keyidx = -1;
+
+       if (net_ratelimit())
+               printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
+                      "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
+                      dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1),
+                      keyidx);
+
+       if (!sta) {
+               /*
+                * Some hardware seem to generate incorrect Michael MIC
+                * reports; ignore them to avoid triggering countermeasures.
+                */
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+                              "error for unknown address " MAC_FMT "\n",
+                              dev->name, MAC_ARG(hdr->addr2));
+               goto ignore;
+       }
+
+       if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+                              "error for a frame with no PROTECTED flag (src "
+                              MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
+               goto ignore;
+       }
+
+       if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
+               /*
+                * APs with pairwise keys should never receive Michael MIC
+                * errors for non-zero keyidx because these are reserved for
+                * group keys and only the AP is sending real multicast
+                * frames in the BSS.
+                */
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: ignored Michael MIC error for "
+                              "a frame with non-zero keyidx (%d)"
+                              " (src " MAC_FMT ")\n", dev->name, keyidx,
+                              MAC_ARG(hdr->addr2));
+               goto ignore;
+       }
+
+       if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+           ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+            (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+                              "error for a frame that cannot be encrypted "
+                              "(fc=0x%04x) (src " MAC_FMT ")\n",
+                              dev->name, rx->fc, MAC_ARG(hdr->addr2));
+               goto ignore;
+       }
+
+       mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr);
+ ignore:
+       dev_kfree_skb(rx->skb);
+       rx->skb = NULL;
+}
+
+ieee80211_rx_handler ieee80211_rx_handlers[] =
+{
+       ieee80211_rx_h_if_stats,
+       ieee80211_rx_h_passive_scan,
+       ieee80211_rx_h_check,
+       ieee80211_rx_h_decrypt,
+       ieee80211_rx_h_sta_process,
+       ieee80211_rx_h_defragment,
+       ieee80211_rx_h_ps_poll,
+       ieee80211_rx_h_michael_mic_verify,
+       /* this must be after decryption - so header is counted in MPDU mic
+        * must be before pae and data, so QOS_DATA format frames
+        * are not passed to user space by these functions
+        */
+       ieee80211_rx_h_remove_qos_control,
+       ieee80211_rx_h_802_1x_pae,
+       ieee80211_rx_h_drop_unencrypted,
+       ieee80211_rx_h_data,
+       ieee80211_rx_h_mgmt,
+       NULL
+};
+
+/* main receive path */
+
+static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
+                               u8 *bssid, struct ieee80211_txrx_data *rx,
+                               struct ieee80211_hdr *hdr)
+{
+       int multicast = is_multicast_ether_addr(hdr->addr1);
+
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_STA:
+               if (!bssid)
+                       return 0;
+               if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+                       if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+                               return 0;
+                       rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+               } else if (!multicast &&
+                          compare_ether_addr(sdata->dev->dev_addr,
+                                             hdr->addr1) != 0) {
+                       if (!(sdata->dev->flags & IFF_PROMISC))
+                               return 0;
+                       rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+               }
+               break;
+       case IEEE80211_IF_TYPE_IBSS:
+               if (!bssid)
+                       return 0;
+               if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+                       if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+                               return 0;
+                       rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+               } else if (!multicast &&
+                          compare_ether_addr(sdata->dev->dev_addr,
+                                             hdr->addr1) != 0) {
+                       if (!(sdata->dev->flags & IFF_PROMISC))
+                               return 0;
+                       rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+               } else if (!rx->sta)
+                       rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
+                                                        bssid, hdr->addr2);
+               break;
+       case IEEE80211_IF_TYPE_VLAN:
+       case IEEE80211_IF_TYPE_AP:
+               if (!bssid) {
+                       if (compare_ether_addr(sdata->dev->dev_addr,
+                                              hdr->addr1))
+                               return 0;
+               } else if (!ieee80211_bssid_match(bssid,
+                                       sdata->dev->dev_addr)) {
+                       if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+                               return 0;
+                       rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+               }
+               if (sdata->dev == sdata->local->mdev &&
+                   !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+                       /* do not receive anything via
+                        * master device when not scanning */
+                       return 0;
+               break;
+       case IEEE80211_IF_TYPE_WDS:
+               if (bssid ||
+                   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+                       return 0;
+               if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
+                       return 0;
+               break;
+       case IEEE80211_IF_TYPE_MNTR:
+               /* take everything */
+               break;
+       case IEEE80211_IF_TYPE_INVALID:
+               /* should never get here */
+               WARN_ON(1);
+               break;
+       }
+
+       return 1;
+}
+
+/*
+ * This is the receive path handler. It is called by a low level driver when an
+ * 802.11 MPDU is received from the hardware.
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                   struct ieee80211_rx_status *status)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_txrx_data rx;
+       u16 type;
+       int prepres;
+       struct ieee80211_sub_if_data *prev = NULL;
+       struct sk_buff *skb_new;
+       u8 *bssid;
+
+       /*
+        * key references and virtual interfaces are protected using RCU
+        * and this requires that we are in a read-side RCU section during
+        * receive processing
+        */
+       rcu_read_lock();
+
+       /*
+        * Frames with failed FCS/PLCP checksum are not returned,
+        * all other frames are returned without radiotap header
+        * if it was previously present.
+        * Also, frames with less than 16 bytes are dropped.
+        */
+       skb = ieee80211_rx_monitor(local, skb, status);
+       if (!skb) {
+               rcu_read_unlock();
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       memset(&rx, 0, sizeof(rx));
+       rx.skb = skb;
+       rx.local = local;
+
+       rx.u.rx.status = status;
+       rx.fc = le16_to_cpu(hdr->frame_control);
+       type = rx.fc & IEEE80211_FCTL_FTYPE;
+
+       if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
+               local->dot11ReceivedFragmentCount++;
+
+       sta = rx.sta = sta_info_get(local, hdr->addr2);
+       if (sta) {
+               rx.dev = rx.sta->dev;
+               rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+       }
+
+       if ((status->flag & RX_FLAG_MMIC_ERROR)) {
+               ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
+               goto end;
+       }
+
+       if (unlikely(local->sta_scanning))
+               rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
+
+       if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
+                                          sta) != TXRX_CONTINUE)
+               goto end;
+       skb = rx.skb;
+
+       if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
+           !atomic_read(&local->iff_promiscs) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
+               rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
+               ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
+                                            rx.sta);
+               sta_info_put(sta);
+               rcu_read_unlock();
+               return;
+       }
+
+       bssid = ieee80211_get_bssid(hdr, skb->len);
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!netif_running(sdata->dev))
+                       continue;
+
+               if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+                       continue;
+
+               rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
+               prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
+               /* prepare_for_handlers can change sta */
+               sta = rx.sta;
+
+               if (!prepres)
+                       continue;
+
+               /*
+                * frame is destined for this interface, but if it's not
+                * also for the previous one we handle that after the
+                * loop to avoid copying the SKB once too much
+                */
+
+               if (!prev) {
+                       prev = sdata;
+                       continue;
+               }
+
+               /*
+                * frame was destined for the previous interface
+                * so invoke RX handlers for it
+                */
+
+               skb_new = skb_copy(skb, GFP_ATOMIC);
+               if (!skb_new) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: failed to copy "
+                                      "multicast frame for %s",
+                                      wiphy_name(local->hw.wiphy),
+                                      prev->dev->name);
+                       continue;
+               }
+               rx.skb = skb_new;
+               rx.dev = prev->dev;
+               rx.sdata = prev;
+               ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+                                            &rx, sta);
+               prev = sdata;
+       }
+       if (prev) {
+               rx.skb = skb;
+               rx.dev = prev->dev;
+               rx.sdata = prev;
+               ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+                                            &rx, sta);
+       } else
+               dev_kfree_skb(skb);
+
+ end:
+       rcu_read_unlock();
+
+       if (sta)
+               sta_info_put(sta);
+}
+EXPORT_SYMBOL(__ieee80211_rx);
+
+/* This is a version of the rx handler that can be called from hard irq
+ * context. Post the skb on the queue and schedule the tasklet */
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         struct ieee80211_rx_status *status)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
+
+       skb->dev = local->mdev;
+       /* copy status into skb->cb for use by tasklet */
+       memcpy(skb->cb, status, sizeof(*status));
+       skb->pkt_type = IEEE80211_RX_MSG;
+       skb_queue_tail(&local->skb_queue, skb);
+       tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_rx_irqsafe);
index 3d21ea0636d1d3620ee7139a00fb067e85826ead..4ed1b60bb1caa23812987231b4218adaf3fe3a11 100644 (file)
@@ -19,7 +19,6 @@
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "sta_info.h"
-#include "debugfs_key.h"
 #include "debugfs_sta.h"
 
 /* Caller must hold local->sta_lock */
@@ -32,42 +31,34 @@ static void sta_info_hash_add(struct ieee80211_local *local,
 
 
 /* Caller must hold local->sta_lock */
-static void sta_info_hash_del(struct ieee80211_local *local,
-                             struct sta_info *sta, int dls)
+static int sta_info_hash_del(struct ieee80211_local *local,
+                            struct sta_info *sta)
 {
        struct sta_info *s;
 
        s = local->sta_hash[STA_HASH(sta->addr)];
        if (!s)
-               return;
-       if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
-               if (dls && !s->dls_sta)
-                       return;
+               return -ENOENT;
+       if (s == sta) {
                local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
-               return;
+               return 0;
        }
 
-       while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
+       while (s->hnext && s->hnext != sta)
                s = s->hnext;
        if (s->hnext) {
-               if (dls && !s->hnext->dls_sta)
-                       return;
-               s->hnext = s->hnext->hnext;
-       } else
-               printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from "
-                      "hash table\n", local->mdev->name, MAC_ARG(sta->addr));
-}
+               s->hnext = sta->hnext;
+               return 0;
+       }
 
-static inline void __sta_info_get(struct sta_info *sta)
-{
-       kref_get(&sta->kref);
+       return -ENOENT;
 }
 
 struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
 {
        struct sta_info *sta;
 
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        sta = local->sta_hash[STA_HASH(addr)];
        while (sta) {
                if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
@@ -76,34 +67,12 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
                }
                sta = sta->hnext;
        }
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
 
        return sta;
 }
 EXPORT_SYMBOL(sta_info_get);
 
-struct sta_info *dls_info_get(struct ieee80211_local *local, u8 *addr)
-{
-       struct sta_info *sta;
-
-       spin_lock_bh(&local->sta_lock);
-       sta = local->sta_hash[STA_HASH(addr)];
-       while (sta) {
-               if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
-                       if (!sta->dls_sta) {
-                               sta = NULL;
-                               break;
-                       }
-                       __sta_info_get(sta);
-                       break;
-               }
-               sta = sta->hnext;
-       }
-       spin_unlock_bh(&local->sta_lock);
-
-       return sta;
-}
-
 int sta_info_min_txrate_get(struct ieee80211_local *local)
 {
        struct sta_info *sta;
@@ -111,7 +80,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local)
        int min_txrate = 9999999;
        int i;
 
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        mode = local->oper_hw_mode;
        for (i = 0; i < STA_HASH_SIZE; i++) {
                sta = local->sta_hash[i];
@@ -121,7 +90,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local)
                        sta = sta->hnext;
                }
        }
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
        if (min_txrate == 9999999)
                min_txrate = 0;
 
@@ -148,8 +117,6 @@ static void sta_info_release(struct kref *kref)
        }
        rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
        rate_control_put(sta->rate_ctrl);
-       if (sta->key)
-               ieee80211_debugfs_key_sta_del(sta->key, sta);
        kfree(sta);
 }
 
@@ -176,7 +143,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
        sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
        if (!sta->rate_ctrl_priv) {
                rate_control_put(sta->rate_ctrl);
-               kref_put(&sta->kref, sta_info_release);
                kfree(sta);
                return NULL;
        }
@@ -188,63 +154,40 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
        skb_queue_head_init(&sta->tx_filtered);
        __sta_info_get(sta);    /* sta used by caller, decremented by
                                 * sta_info_put() */
-       spin_lock_bh(&local->sta_lock);
+       write_lock_bh(&local->sta_lock);
        list_add(&sta->list, &local->sta_list);
        local->num_sta++;
        sta_info_hash_add(local, sta);
-       spin_unlock_bh(&local->sta_lock);
-       if (local->ops->sta_table_notification)
-               local->ops->sta_table_notification(local_to_hw(local),
-                                                 local->num_sta);
-       sta->key_idx_compression = HW_KEY_IDX_INVALID;
+       if (local->ops->sta_notify)
+               local->ops->sta_notify(local_to_hw(local), dev->ifindex,
+                                       STA_NOTIFY_ADD, addr);
+       write_unlock_bh(&local->sta_lock);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
-              local->mdev->name, MAC_ARG(addr));
+              wiphy_name(local->hw.wiphy), MAC_ARG(addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-       if (!in_interrupt()) {
-               sta->debugfs_registered = 1;
-               ieee80211_sta_debugfs_add(sta);
-               rate_control_add_sta_debugfs(sta);
-       } else {
-               /* debugfs entry adding might sleep, so schedule process
-                * context task for adding entry for STAs that do not yet
-                * have one. */
-               queue_work(local->hw.workqueue, &local->sta_debugfs_add);
-       }
+       /* debugfs entry adding might sleep, so schedule process
+        * context task for adding entry for STAs that do not yet
+        * have one. */
+       queue_work(local->hw.workqueue, &local->sta_debugfs_add);
 #endif
 
        return sta;
 }
 
-static void finish_sta_info_free(struct ieee80211_local *local,
-                                struct sta_info *sta)
-{
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
-              local->mdev->name, MAC_ARG(sta->addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-
-       if (sta->key) {
-               ieee80211_debugfs_key_remove(sta->key);
-               ieee80211_key_free(sta->key);
-               sta->key = NULL;
-       }
-
-       rate_control_remove_sta_debugfs(sta);
-       ieee80211_sta_debugfs_remove(sta);
-
-       sta_info_put(sta);
-}
-
-static void sta_info_remove(struct sta_info *sta)
+/* Caller must hold local->sta_lock */
+void sta_info_remove(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata;
 
-       sta_info_hash_del(local, sta, 0);
+       /* don't do anything if we've been removed already */
+       if (sta_info_hash_del(local, sta))
+               return;
+
        list_del(&sta->list);
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
        if (sta->flags & WLAN_STA_PS) {
@@ -254,61 +197,44 @@ static void sta_info_remove(struct sta_info *sta)
        }
        local->num_sta--;
        sta_info_remove_aid_ptr(sta);
+
 }
 
-void sta_info_free(struct sta_info *sta, int locked)
+void sta_info_free(struct sta_info *sta)
 {
        struct sk_buff *skb;
        struct ieee80211_local *local = sta->local;
 
-       if (!locked) {
-               spin_lock_bh(&local->sta_lock);
-               sta_info_remove(sta);
-               spin_unlock_bh(&local->sta_lock);
-       } else {
-               sta_info_remove(sta);
-       }
-       if (local->ops->sta_table_notification)
-               local->ops->sta_table_notification(local_to_hw(local),
-                                                 local->num_sta);
+       might_sleep();
+
+       write_lock_bh(&local->sta_lock);
+       sta_info_remove(sta);
+       write_unlock_bh(&local->sta_lock);
 
        while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
                local->total_ps_buffered--;
-               dev_kfree_skb_any(skb);
+               dev_kfree_skb(skb);
        }
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               dev_kfree_skb_any(skb);
+               dev_kfree_skb(skb);
        }
 
-       if (sta->key) {
-               if (local->ops->set_key) {
-                       struct ieee80211_key_conf *key;
-                       key = ieee80211_key_data2conf(local, sta->key);
-                       if (key) {
-                               local->ops->set_key(local_to_hw(local),
-                                                  DISABLE_KEY,
-                                                  sta->addr, key, sta->aid);
-                               kfree(key);
-                       }
-               }
-       } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) {
-               struct ieee80211_key_conf conf;
-               memset(&conf, 0, sizeof(conf));
-               conf.hw_key_idx = sta->key_idx_compression;
-               conf.alg = ALG_NULL;
-               conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
-               local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-                                  sta->addr, &conf, sta->aid);
-               sta->key_idx_compression = HW_KEY_IDX_INVALID;
-       }
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
+              wiphy_name(local->hw.wiphy), MAC_ARG(sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-#ifdef CONFIG_MAC80211_DEBUGFS
-       if (in_atomic()) {
-               list_add(&sta->list, &local->deleted_sta_list);
-               queue_work(local->hw.workqueue, &local->sta_debugfs_add);
-       } else
-#endif
-               finish_sta_info_free(local, sta);
+       ieee80211_key_free(sta->key);
+       sta->key = NULL;
+
+       if (local->ops->sta_notify)
+               local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex,
+                                       STA_NOTIFY_REMOVE, sta->addr);
+
+       rate_control_remove_sta_debugfs(sta);
+       ieee80211_sta_debugfs_remove(sta);
+
+       sta_info_put(sta);
 }
 
 
@@ -369,13 +295,13 @@ static void sta_info_cleanup(unsigned long data)
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sta_info *sta;
 
-       spin_lock_bh(&local->sta_lock);
+       read_lock_bh(&local->sta_lock);
        list_for_each_entry(sta, &local->sta_list, list) {
                __sta_info_get(sta);
                sta_info_cleanup_expire_buffered(local, sta);
                sta_info_put(sta);
        }
-       spin_unlock_bh(&local->sta_lock);
+       read_unlock_bh(&local->sta_lock);
 
        local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
        add_timer(&local->sta_cleanup);
@@ -388,36 +314,21 @@ static void sta_info_debugfs_add_task(struct work_struct *work)
                container_of(work, struct ieee80211_local, sta_debugfs_add);
        struct sta_info *sta, *tmp;
 
-       while (1) {
-               spin_lock_bh(&local->sta_lock);
-               if (!list_empty(&local->deleted_sta_list)) {
-                       sta = list_entry(local->deleted_sta_list.next,
-                                        struct sta_info, list);
-                       list_del(local->deleted_sta_list.next);
-               } else
-                       sta = NULL;
-               spin_unlock_bh(&local->sta_lock);
-               if (!sta)
-                       break;
-               finish_sta_info_free(local, sta);
-       }
-
        while (1) {
                sta = NULL;
-               spin_lock_bh(&local->sta_lock);
+               read_lock_bh(&local->sta_lock);
                list_for_each_entry(tmp, &local->sta_list, list) {
-                       if (!tmp->debugfs_registered) {
+                       if (!tmp->debugfs.dir) {
                                sta = tmp;
                                __sta_info_get(sta);
                                break;
                        }
                }
-               spin_unlock_bh(&local->sta_lock);
+               read_unlock_bh(&local->sta_lock);
 
                if (!sta)
                        break;
 
-               sta->debugfs_registered = 1;
                ieee80211_sta_debugfs_add(sta);
                rate_control_add_sta_debugfs(sta);
                sta_info_put(sta);
@@ -427,9 +338,8 @@ static void sta_info_debugfs_add_task(struct work_struct *work)
 
 void sta_info_init(struct ieee80211_local *local)
 {
-       spin_lock_init(&local->sta_lock);
+       rwlock_init(&local->sta_lock);
        INIT_LIST_HEAD(&local->sta_list);
-       INIT_LIST_HEAD(&local->deleted_sta_list);
 
        init_timer(&local->sta_cleanup);
        local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
@@ -449,17 +359,8 @@ int sta_info_start(struct ieee80211_local *local)
 
 void sta_info_stop(struct ieee80211_local *local)
 {
-       struct sta_info *sta, *tmp;
-
        del_timer(&local->sta_cleanup);
-
-       list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               /* sta_info_free must be called with 0 as the last
-                * parameter to ensure all debugfs sta entries are
-                * unregistered. We don't need locking at this
-                * point. */
-               sta_info_free(sta, 0);
-       }
+       sta_info_flush(local, NULL);
 }
 
 void sta_info_remove_aid_ptr(struct sta_info *sta)
@@ -487,10 +388,19 @@ void sta_info_remove_aid_ptr(struct sta_info *sta)
 void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
 {
        struct sta_info *sta, *tmp;
+       LIST_HEAD(tmp_list);
 
-       spin_lock_bh(&local->sta_lock);
+       write_lock_bh(&local->sta_lock);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
-               if (!dev || dev == sta->dev)
-                       sta_info_free(sta, 1);
-       spin_unlock_bh(&local->sta_lock);
+               if (!dev || dev == sta->dev) {
+                       __sta_info_get(sta);
+                       sta_info_remove(sta);
+                       list_add_tail(&sta->list, &tmp_list);
+               }
+       write_unlock_bh(&local->sta_lock);
+
+       list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
+               sta_info_free(sta);
+               sta_info_put(sta);
+       }
 }
index 1179c329738637d970512c4b1913742525362a7d..8f7ebe41c0246a91d687a1ac91e79509dc062b5f 100644 (file)
@@ -26,8 +26,9 @@
                                    * send and receive non-IEEE 802.1X frames
                                    */
 #define WLAN_STA_SHORT_PREAMBLE BIT(7)
+/* whether this is an AP that we are associated with as a client */
+#define WLAN_STA_ASSOC_AP BIT(8)
 #define WLAN_STA_WME BIT(9)
-#define WLAN_STA_HT  BIT(10)
 #define WLAN_STA_WDS BIT(27)
 
 
@@ -91,37 +92,11 @@ struct sta_info {
        int channel_use;
        int channel_use_raw;
 
-       u8 antenna_sel_tx;
-       u8 antenna_sel_rx;
-
-
-       int key_idx_compression; /* key table index for compression and TX
-                                 * filtering; used only if sta->key is not
-                                 * set */
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-       int debugfs_registered;
-#endif
-       unsigned int assoc_ap:1; /* whether this is an AP that we are
-                                 * associated with as a client */
-       unsigned int dls_sta:1; /* whether this stations is a DLS peer of us */
-
-#define DLS_STATUS_OK          0
-#define DLS_STATUS_NOLINK      1
-       int dls_status;
-       u32 dls_timeout;
-
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       u32 wpa_trigger;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
        unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
        unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
 
-       int vlan_id;
-
        u16 listen_interval;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -160,12 +135,18 @@ struct sta_info {
  */
 #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
 
+static inline void __sta_info_get(struct sta_info *sta)
+{
+       kref_get(&sta->kref);
+}
+
 struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
 int sta_info_min_txrate_get(struct ieee80211_local *local);
 void sta_info_put(struct sta_info *sta);
 struct sta_info * sta_info_add(struct ieee80211_local *local,
                               struct net_device *dev, u8 *addr, gfp_t gfp);
-void sta_info_free(struct sta_info *sta, int locked);
+void sta_info_remove(struct sta_info *sta);
+void sta_info_free(struct sta_info *sta);
 void sta_info_init(struct ieee80211_local *local);
 int sta_info_start(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
index 41621720e5601d4e6344598431fedb7148aa94b8..876cbe37107a3138dacc4072609841daba764948 100644 (file)
@@ -182,7 +182,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
        *pos++ = iv0;
        *pos++ = iv1;
        *pos++ = iv2;
-       *pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */;
+       *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
        *pos++ = key->u.tkip.iv32 & 0xff;
        *pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
        *pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
@@ -194,7 +194,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
 void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
                                  u16 *phase1key)
 {
-       tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+       tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
                           key->u.tkip.iv32, phase1key);
 }
 
@@ -204,12 +204,13 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
        /* Calculate per-packet key */
        if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
                /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+               tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
                                   key->u.tkip.iv32, key->u.tkip.p1k);
                key->u.tkip.tx_initialized = 1;
        }
 
-       tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+       tkip_mixing_phase2(key->u.tkip.p1k,
+                          &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
                           key->u.tkip.iv16, rc4key);
 }
 
@@ -237,7 +238,8 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
 int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                                struct ieee80211_key *key,
                                u8 *payload, size_t payload_len, u8 *ta,
-                               int only_iv, int queue)
+                               int only_iv, int queue,
+                               u32 *out_iv32, u16 *out_iv16)
 {
        u32 iv32;
        u32 iv16;
@@ -266,7 +268,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        if (!(keyid & (1 << 5)))
                return TKIP_DECRYPT_NO_EXT_IV;
 
-       if ((keyid >> 6) != key->keyidx)
+       if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
        if (key->u.tkip.rx_initialized[queue] &&
@@ -293,7 +295,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
            key->u.tkip.iv32_rx[queue] != iv32) {
                key->u.tkip.rx_initialized[queue] = 1;
                /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+               tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
                                   iv32, key->u.tkip.p1k_rx[queue]);
 #ifdef CONFIG_TKIP_DEBUG
                {
@@ -302,7 +304,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                               " TK=", MAC_ARG(ta));
                        for (i = 0; i < 16; i++)
                                printk("%02x ",
-                                      key->key[ALG_TKIP_TEMP_ENCR_KEY + i]);
+                                      key->conf.key[
+                                               ALG_TKIP_TEMP_ENCR_KEY + i]);
                        printk("\n");
                        printk(KERN_DEBUG "TKIP decrypt: P1K=");
                        for (i = 0; i < 5; i++)
@@ -313,7 +316,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        }
 
        tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
-                          &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+                          &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
                           iv16, rc4key);
 #ifdef CONFIG_TKIP_DEBUG
        {
@@ -328,11 +331,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
        if (res == TKIP_DECRYPT_OK) {
-               /* FIX: these should be updated only after Michael MIC has been
-                * verified */
-               /* Record previously received IV */
-               key->u.tkip.iv32_rx[queue] = iv32;
-               key->u.tkip.iv16_rx[queue] = iv16;
+               /*
+                * Record previously received IV, will be copied into the
+                * key information after MIC verification. It is possible
+                * that we don't catch replays of fragments but that's ok
+                * because the Michael MIC verication will then fail.
+                */
+               *out_iv32 = iv32;
+               *out_iv16 = iv16;
        }
 
        return res;
index a0d181a180495f786156790bbec9dc4470ce7430..73d8ef2a93b0f9ed5821d3a0686b44e65f6e0c63 100644 (file)
@@ -31,6 +31,7 @@ enum {
 int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                                struct ieee80211_key *key,
                                u8 *payload, size_t payload_len, u8 *ta,
-                               int only_iv, int queue);
+                               int only_iv, int queue,
+                               u32 *out_iv32, u16 *out_iv16);
 
 #endif /* TKIP_H */
diff --git a/package/mac80211/src/mac80211/tx.c b/package/mac80211/src/mac80211/tx.c
new file mode 100644 (file)
index 0000000..957ec3c
--- /dev/null
@@ -0,0 +1,1898 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * Transmit and frame generation functions.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/bitmap.h>
+#include <linux/rcupdate.h>
+#include <net/ieee80211_radiotap.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "ieee80211_led.h"
+#include "wep.h"
+#include "wpa.h"
+#include "wme.h"
+#include "ieee80211_rate.h"
+
+#define IEEE80211_TX_OK                0
+#define IEEE80211_TX_AGAIN     1
+#define IEEE80211_TX_FRAG_AGAIN        2
+
+/* misc utils */
+
+static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+                                             struct ieee80211_hdr *hdr)
+{
+       /* Set the sequence number for this frame. */
+       hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
+
+       /* Increase the sequence number. */
+       sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
+#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
+static void ieee80211_dump_frame(const char *ifname, const char *title,
+                                const struct sk_buff *skb)
+{
+       const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u16 fc;
+       int hdrlen;
+
+       printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
+       if (skb->len < 4) {
+               printk("\n");
+               return;
+       }
+
+       fc = le16_to_cpu(hdr->frame_control);
+       hdrlen = ieee80211_get_hdrlen(fc);
+       if (hdrlen > skb->len)
+               hdrlen = skb->len;
+       if (hdrlen >= 4)
+               printk(" FC=0x%04x DUR=0x%04x",
+                      fc, le16_to_cpu(hdr->duration_id));
+       if (hdrlen >= 10)
+               printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1));
+       if (hdrlen >= 16)
+               printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
+       if (hdrlen >= 24)
+               printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
+       if (hdrlen >= 30)
+               printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
+       printk("\n");
+}
+#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+static inline void ieee80211_dump_frame(const char *ifname, const char *title,
+                                       struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+
+static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
+                             int next_frag_len)
+{
+       int rate, mrate, erp, dur, i;
+       struct ieee80211_rate *txrate = tx->u.tx.rate;
+       struct ieee80211_local *local = tx->local;
+       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+       erp = txrate->flags & IEEE80211_RATE_ERP;
+
+       /*
+        * data and mgmt (except PS Poll):
+        * - during CFP: 32768
+        * - during contention period:
+        *   if addr1 is group address: 0
+        *   if more fragments = 0 and addr1 is individual address: time to
+        *      transmit one ACK plus SIFS
+        *   if more fragments = 1 and addr1 is individual address: time to
+        *      transmit next fragment plus 2 x ACK plus 3 x SIFS
+        *
+        * IEEE 802.11, 9.6:
+        * - control response frame (CTS or ACK) shall be transmitted using the
+        *   same rate as the immediately previous frame in the frame exchange
+        *   sequence, if this rate belongs to the PHY mandatory rates, or else
+        *   at the highest possible rate belonging to the PHY rates in the
+        *   BSSBasicRateSet
+        */
+
+       if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {
+               /* TODO: These control frames are not currently sent by
+                * 80211.o, but should they be implemented, this function
+                * needs to be updated to support duration field calculation.
+                *
+                * RTS: time needed to transmit pending data/mgmt frame plus
+                *    one CTS frame plus one ACK frame plus 3 x SIFS
+                * CTS: duration of immediately previous RTS minus time
+                *    required to transmit CTS and its SIFS
+                * ACK: 0 if immediately previous directed data/mgmt had
+                *    more=0, with more=1 duration in ACK frame is duration
+                *    from previous frame minus time needed to transmit ACK
+                *    and its SIFS
+                * PS Poll: BIT(15) | BIT(14) | aid
+                */
+               return 0;
+       }
+
+       /* data/mgmt */
+       if (0 /* FIX: data/mgmt during CFP */)
+               return 32768;
+
+       if (group_addr) /* Group address as the destination - no ACK */
+               return 0;
+
+       /* Individual destination address:
+        * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
+        * CTS and ACK frames shall be transmitted using the highest rate in
+        * basic rate set that is less than or equal to the rate of the
+        * immediately previous frame and that is using the same modulation
+        * (CCK or OFDM). If no basic rate set matches with these requirements,
+        * the highest mandatory rate of the PHY that is less than or equal to
+        * the rate of the previous frame is used.
+        * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
+        */
+       rate = -1;
+       mrate = 10; /* use 1 Mbps if everything fails */
+       for (i = 0; i < mode->num_rates; i++) {
+               struct ieee80211_rate *r = &mode->rates[i];
+               if (r->rate > txrate->rate)
+                       break;
+
+               if (IEEE80211_RATE_MODULATION(txrate->flags) !=
+                   IEEE80211_RATE_MODULATION(r->flags))
+                       continue;
+
+               if (r->flags & IEEE80211_RATE_BASIC)
+                       rate = r->rate;
+               else if (r->flags & IEEE80211_RATE_MANDATORY)
+                       mrate = r->rate;
+       }
+       if (rate == -1) {
+               /* No matching basic rate found; use highest suitable mandatory
+                * PHY rate */
+               rate = mrate;
+       }
+
+       /* Time needed to transmit ACK
+        * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
+        * to closest integer */
+
+       dur = ieee80211_frame_duration(local, 10, rate, erp,
+                      tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
+
+       if (next_frag_len) {
+               /* Frame is fragmented: duration increases with time needed to
+                * transmit next fragment plus ACK and 2 x SIFS. */
+               dur *= 2; /* ACK + SIFS */
+               /* next fragment */
+               dur += ieee80211_frame_duration(local, next_frag_len,
+                               txrate->rate, erp,
+                               tx->sdata->flags &
+                                       IEEE80211_SDATA_SHORT_PREAMBLE);
+       }
+
+       return dur;
+}
+
+static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
+                                           int queue)
+{
+       return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+
+static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
+                                           int queue)
+{
+       return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
+}
+
+static int inline is_ieee80211_device(struct net_device *dev,
+                                     struct net_device *master)
+{
+       return (wdev_priv(dev->ieee80211_ptr) ==
+               wdev_priv(master->ieee80211_ptr));
+}
+
+/* tx handlers */
+
+static ieee80211_txrx_result
+ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       struct sk_buff *skb = tx->skb;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       u32 sta_flags;
+
+       if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
+               return TXRX_CONTINUE;
+
+       if (unlikely(tx->local->sta_scanning != 0) &&
+           ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+            (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
+               return TXRX_DROP;
+
+       if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
+               return TXRX_CONTINUE;
+
+       sta_flags = tx->sta ? tx->sta->flags : 0;
+
+       if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) {
+               if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
+                            tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+                            (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       printk(KERN_DEBUG "%s: dropped data frame to not "
+                              "associated station " MAC_FMT "\n",
+                              tx->dev->name, MAC_ARG(hdr->addr1));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+                       I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
+                       return TXRX_DROP;
+               }
+       } else {
+               if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+                            tx->local->num_sta == 0 &&
+                            tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
+                       /*
+                        * No associated STAs - no need to send multicast
+                        * frames.
+                        */
+                       return TXRX_DROP;
+               }
+               return TXRX_CONTINUE;
+       }
+
+       if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
+                    !(sta_flags & WLAN_STA_AUTHORIZED))) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
+                      " (unauthorized port)\n", tx->dev->name,
+                      MAC_ARG(hdr->addr1));
+#endif
+               I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
+               return TXRX_DROP;
+       }
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+       if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+               ieee80211_include_sequence(tx->sdata, hdr);
+
+       return TXRX_CONTINUE;
+}
+
+/* This function is called whenever the AP is about to exceed the maximum limit
+ * of buffered frames for power saving STAs. This situation should not really
+ * happen often during normal operation, so dropping the oldest buffered packet
+ * from each queue should be OK to make some room for new frames. */
+static void purge_old_ps_buffers(struct ieee80211_local *local)
+{
+       int total = 0, purged = 0;
+       struct sk_buff *skb;
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
+
+       /*
+        * virtual interfaces are protected by RCU
+        */
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               struct ieee80211_if_ap *ap;
+               if (sdata->dev == local->mdev ||
+                   sdata->type != IEEE80211_IF_TYPE_AP)
+                       continue;
+               ap = &sdata->u.ap;
+               skb = skb_dequeue(&ap->ps_bc_buf);
+               if (skb) {
+                       purged++;
+                       dev_kfree_skb(skb);
+               }
+               total += skb_queue_len(&ap->ps_bc_buf);
+       }
+       rcu_read_unlock();
+
+       read_lock_bh(&local->sta_lock);
+       list_for_each_entry(sta, &local->sta_list, list) {
+               skb = skb_dequeue(&sta->ps_tx_buf);
+               if (skb) {
+                       purged++;
+                       dev_kfree_skb(skb);
+               }
+               total += skb_queue_len(&sta->ps_tx_buf);
+       }
+       read_unlock_bh(&local->sta_lock);
+
+       local->total_ps_buffered = total;
+       printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
+              wiphy_name(local->hw.wiphy), purged);
+}
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+       /* broadcast/multicast frame */
+       /* If any of the associated stations is in power save mode,
+        * the frame is buffered to be sent after DTIM beacon frame */
+       if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&
+           tx->sdata->type != IEEE80211_IF_TYPE_WDS &&
+           tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&
+           !(tx->fc & IEEE80211_FCTL_ORDER)) {
+               if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+                       purge_old_ps_buffers(tx->local);
+               if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
+                   AP_MAX_BC_BUFFER) {
+                       if (net_ratelimit()) {
+                               printk(KERN_DEBUG "%s: BC TX buffer full - "
+                                      "dropping the oldest frame\n",
+                                      tx->dev->name);
+                       }
+                       dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
+               } else
+                       tx->local->total_ps_buffered++;
+               skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
+               return TXRX_QUEUED;
+       }
+
+       return TXRX_CONTINUE;
+}
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+       struct sta_info *sta = tx->sta;
+
+       if (unlikely(!sta ||
+                    ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+                     (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
+               return TXRX_CONTINUE;
+
+       if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
+               struct ieee80211_tx_packet_data *pkt_data;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+               printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries "
+                      "before %d)\n",
+                      MAC_ARG(sta->addr), sta->aid,
+                      skb_queue_len(&sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+               sta->flags |= WLAN_STA_TIM;
+               if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+                       purge_old_ps_buffers(tx->local);
+               if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
+                       struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
+                       if (net_ratelimit()) {
+                               printk(KERN_DEBUG "%s: STA " MAC_FMT " TX "
+                                      "buffer full - dropping oldest frame\n",
+                                      tx->dev->name, MAC_ARG(sta->addr));
+                       }
+                       dev_kfree_skb(old);
+               } else
+                       tx->local->total_ps_buffered++;
+               /* Queue frame to be sent after STA sends an PS Poll frame */
+               if (skb_queue_empty(&sta->ps_tx_buf)) {
+                       if (tx->local->ops->set_tim)
+                               tx->local->ops->set_tim(local_to_hw(tx->local),
+                                                      sta->aid, 1);
+                       if (tx->sdata->bss)
+                               bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
+               }
+               pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
+               pkt_data->jiffies = jiffies;
+               skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+               return TXRX_QUEUED;
+       }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+       else if (unlikely(sta->flags & WLAN_STA_PS)) {
+               printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll "
+                      "set -> send frame\n", tx->dev->name,
+                      MAC_ARG(sta->addr));
+       }
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+       sta->pspoll = 0;
+
+       return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
+{
+       if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))
+               return TXRX_CONTINUE;
+
+       if (tx->flags & IEEE80211_TXRXD_TXUNICAST)
+               return ieee80211_tx_h_unicast_ps_buf(tx);
+       else
+               return ieee80211_tx_h_multicast_ps_buf(tx);
+}
+
+
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_key *key;
+
+       if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+               tx->key = NULL;
+       else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
+               tx->key = key;
+       else if ((key = rcu_dereference(tx->sdata->default_key)))
+               tx->key = key;
+       else if (tx->sdata->drop_unencrypted &&
+                !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
+               I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
+               return TXRX_DROP;
+       } else {
+               tx->key = NULL;
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+       }
+
+       if (tx->key) {
+               tx->key->tx_rx_count++;
+               /* TODO: add threshold stuff again */
+       }
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+       size_t hdrlen, per_fragm, num_fragm, payload_len, left;
+       struct sk_buff **frags, *first, *frag;
+       int i;
+       u16 seq;
+       u8 *pos;
+       int frag_threshold = tx->local->fragmentation_threshold;
+
+       if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED))
+               return TXRX_CONTINUE;
+
+       first = tx->skb;
+
+       hdrlen = ieee80211_get_hdrlen(tx->fc);
+       payload_len = first->len - hdrlen;
+       per_fragm = frag_threshold - hdrlen - FCS_LEN;
+       num_fragm = (payload_len + per_fragm - 1) / per_fragm;
+
+       frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
+       if (!frags)
+               goto fail;
+
+       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+       seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
+       pos = first->data + hdrlen + per_fragm;
+       left = payload_len - per_fragm;
+       for (i = 0; i < num_fragm - 1; i++) {
+               struct ieee80211_hdr *fhdr;
+               size_t copylen;
+
+               if (left <= 0)
+                       goto fail;
+
+               /* reserve enough extra head and tail room for possible
+                * encryption */
+               frag = frags[i] =
+                       dev_alloc_skb(tx->local->tx_headroom +
+                                     frag_threshold +
+                                     IEEE80211_ENCRYPT_HEADROOM +
+                                     IEEE80211_ENCRYPT_TAILROOM);
+               if (!frag)
+                       goto fail;
+               /* Make sure that all fragments use the same priority so
+                * that they end up using the same TX queue */
+               frag->priority = first->priority;
+               skb_reserve(frag, tx->local->tx_headroom +
+                                 IEEE80211_ENCRYPT_HEADROOM);
+               fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
+               memcpy(fhdr, first->data, hdrlen);
+               if (i == num_fragm - 2)
+                       fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+               fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
+               copylen = left > per_fragm ? per_fragm : left;
+               memcpy(skb_put(frag, copylen), pos, copylen);
+
+               pos += copylen;
+               left -= copylen;
+       }
+       skb_trim(first, hdrlen + per_fragm);
+
+       tx->u.tx.num_extra_frag = num_fragm - 1;
+       tx->u.tx.extra_frag = frags;
+
+       return TXRX_CONTINUE;
+
+ fail:
+       printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
+       if (frags) {
+               for (i = 0; i < num_fragm - 1; i++)
+                       if (frags[i])
+                               dev_kfree_skb(frags[i]);
+               kfree(frags);
+       }
+       I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
+       return TXRX_DROP;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
+{
+       if (!tx->key)
+               return TXRX_CONTINUE;
+
+       switch (tx->key->conf.alg) {
+       case ALG_WEP:
+               return ieee80211_crypto_wep_encrypt(tx);
+       case ALG_TKIP:
+               return ieee80211_crypto_tkip_encrypt(tx);
+       case ALG_CCMP:
+               return ieee80211_crypto_ccmp_encrypt(tx);
+       }
+
+       /* not reached */
+       WARN_ON(1);
+       return TXRX_DROP;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
+{
+       struct rate_control_extra extra;
+
+       if (likely(!tx->u.tx.rate)) {
+               memset(&extra, 0, sizeof(extra));
+               extra.mode = tx->u.tx.mode;
+               extra.ethertype = tx->ethertype;
+
+               tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
+                                                     tx->skb, &extra);
+               if (unlikely(extra.probe != NULL)) {
+                       tx->u.tx.control->flags |=
+                               IEEE80211_TXCTL_RATE_CTRL_PROBE;
+                       tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+                       tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
+                       tx->u.tx.rate = extra.probe;
+               } else
+                       tx->u.tx.control->alt_retry_rate = -1;
+
+               if (!tx->u.tx.rate)
+                       return TXRX_DROP;
+       } else
+               tx->u.tx.control->alt_retry_rate = -1;
+
+       if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
+           (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
+           (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) {
+               tx->u.tx.last_frag_rate = tx->u.tx.rate;
+               if (extra.probe)
+                       tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+               else
+                       tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+               tx->u.tx.rate = extra.nonerp;
+               tx->u.tx.control->rate = extra.nonerp;
+               tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+       } else {
+               tx->u.tx.last_frag_rate = tx->u.tx.rate;
+               tx->u.tx.control->rate = tx->u.tx.rate;
+       }
+       tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+       u16 fc = le16_to_cpu(hdr->frame_control);
+       u16 dur;
+       struct ieee80211_tx_control *control = tx->u.tx.control;
+       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+       if (!control->retry_limit) {
+               if (!is_multicast_ether_addr(hdr->addr1)) {
+                       if (tx->skb->len + FCS_LEN > tx->local->rts_threshold
+                           && tx->local->rts_threshold <
+                                       IEEE80211_MAX_RTS_THRESHOLD) {
+                               control->flags |=
+                                       IEEE80211_TXCTL_USE_RTS_CTS;
+                               control->flags |=
+                                       IEEE80211_TXCTL_LONG_RETRY_LIMIT;
+                               control->retry_limit =
+                                       tx->local->long_retry_limit;
+                       } else {
+                               control->retry_limit =
+                                       tx->local->short_retry_limit;
+                       }
+               } else {
+                       control->retry_limit = 1;
+               }
+       }
+
+       if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
+               /* Do not use multiple retry rates when sending fragmented
+                * frames.
+                * TODO: The last fragment could still use multiple retry
+                * rates. */
+               control->alt_retry_rate = -1;
+       }
+
+       /* Use CTS protection for unicast frames sent using extended rates if
+        * there are associated non-ERP stations and RTS/CTS is not configured
+        * for the frame. */
+       if (mode->mode == MODE_IEEE80211G &&
+           (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
+           (tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+           (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
+           !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
+               control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
+
+       /* Transmit data frames using short preambles if the driver supports
+        * short preambles at the selected rate and short preambles are
+        * available on the network at the current point in time. */
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+           (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+           (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
+           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
+               tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+       }
+
+       /* Setup duration field for the first fragment of the frame. Duration
+        * for remaining fragments will be updated when they are being sent
+        * to low-level driver in ieee80211_tx(). */
+       dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+                                (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ?
+                                tx->u.tx.extra_frag[0]->len : 0);
+       hdr->duration_id = cpu_to_le16(dur);
+
+       if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+           (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+               struct ieee80211_rate *rate;
+
+               /* Do not use multiple retry rates when using RTS/CTS */
+               control->alt_retry_rate = -1;
+
+               /* Use min(data rate, max base rate) as CTS/RTS rate */
+               rate = tx->u.tx.rate;
+               while (rate > mode->rates &&
+                      !(rate->flags & IEEE80211_RATE_BASIC))
+                       rate--;
+
+               control->rts_cts_rate = rate->val;
+               control->rts_rate = rate;
+       }
+
+       if (tx->sta) {
+               tx->sta->tx_packets++;
+               tx->sta->tx_fragments++;
+               tx->sta->tx_bytes += tx->skb->len;
+               if (tx->u.tx.extra_frag) {
+                       int i;
+                       tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
+                       for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+                               tx->sta->tx_bytes +=
+                                       tx->u.tx.extra_frag[i]->len;
+                       }
+               }
+       }
+
+       /*
+        * Tell hardware to not encrypt when we had sw crypto.
+        * Because we use the same flag to internally indicate that
+        * no (software) encryption should be done, we have to set it
+        * after all crypto handlers.
+        */
+       if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+
+       return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_local *local = tx->local;
+       struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+       struct sk_buff *skb = tx->skb;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u32 load = 0, hdrtime;
+
+       /* TODO: this could be part of tx_status handling, so that the number
+        * of retries would be known; TX rate should in that case be stored
+        * somewhere with the packet */
+
+       /* Estimate total channel use caused by this frame */
+
+       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+       if (mode->mode == MODE_IEEE80211A ||
+           (mode->mode == MODE_IEEE80211G &&
+            tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+               hdrtime = CHAN_UTIL_HDR_SHORT;
+       else
+               hdrtime = CHAN_UTIL_HDR_LONG;
+
+       load = hdrtime;
+       if (!is_multicast_ether_addr(hdr->addr1))
+               load += hdrtime;
+
+       if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+               load += 2 * hdrtime;
+       else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+               load += hdrtime;
+
+       load += skb->len * tx->u.tx.rate->rate_inv;
+
+       if (tx->u.tx.extra_frag) {
+               int i;
+               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+                       load += 2 * hdrtime;
+                       load += tx->u.tx.extra_frag[i]->len *
+                               tx->u.tx.rate->rate;
+               }
+       }
+
+       /* Divide channel_use by 8 to avoid wrapping around the counter */
+       load >>= CHAN_UTIL_SHIFT;
+       local->channel_use_raw += load;
+       if (tx->sta)
+               tx->sta->channel_use_raw += load;
+       tx->sdata->channel_use_raw += load;
+
+       return TXRX_CONTINUE;
+}
+
+/* TODO: implement register/unregister functions for adding TX/RX handlers
+ * into ordered list */
+
+ieee80211_tx_handler ieee80211_tx_handlers[] =
+{
+       ieee80211_tx_h_check_assoc,
+       ieee80211_tx_h_sequence,
+       ieee80211_tx_h_ps_buf,
+       ieee80211_tx_h_select_key,
+       ieee80211_tx_h_michael_mic_add,
+       ieee80211_tx_h_fragment,
+       ieee80211_tx_h_encrypt,
+       ieee80211_tx_h_rate_ctrl,
+       ieee80211_tx_h_misc,
+       ieee80211_tx_h_load_stats,
+       NULL
+};
+
+/* actual transmit path */
+
+/*
+ * deal with packet injection down monitor interface
+ * with Radiotap Header -- only called for monitor mode interface
+ */
+static ieee80211_txrx_result
+__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
+                             struct sk_buff *skb)
+{
+       /*
+        * this is the moment to interpret and discard the radiotap header that
+        * must be at the start of the packet injected in Monitor mode
+        *
+        * Need to take some care with endian-ness since radiotap
+        * args are little-endian
+        */
+
+       struct ieee80211_radiotap_iterator iterator;
+       struct ieee80211_radiotap_header *rthdr =
+               (struct ieee80211_radiotap_header *) skb->data;
+       struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+       int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+       struct ieee80211_tx_control *control = tx->u.tx.control;
+
+       control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+       tx->flags |= IEEE80211_TXRXD_TX_INJECTED;
+       tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+
+       /*
+        * for every radiotap entry that is present
+        * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+        * entries present, or -EINVAL on error)
+        */
+
+       while (!ret) {
+               int i, target_rate;
+
+               ret = ieee80211_radiotap_iterator_next(&iterator);
+
+               if (ret)
+                       continue;
+
+               /* see if this argument is something we can use */
+               switch (iterator.this_arg_index) {
+               /*
+                * You must take care when dereferencing iterator.this_arg
+                * for multibyte types... the pointer is not aligned.  Use
+                * get_unaligned((type *)iterator.this_arg) to dereference
+                * iterator.this_arg for type "type" safely on all arches.
+               */
+               case IEEE80211_RADIOTAP_RATE:
+                       /*
+                        * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
+                        * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
+                        */
+                       target_rate = (*iterator.this_arg) * 5;
+                       for (i = 0; i < mode->num_rates; i++) {
+                               struct ieee80211_rate *r = &mode->rates[i];
+
+                               if (r->rate == target_rate) {
+                                       tx->u.tx.rate = r;
+                                       break;
+                               }
+                       }
+                       break;
+
+               case IEEE80211_RADIOTAP_ANTENNA:
+                       /*
+                        * radiotap uses 0 for 1st ant, mac80211 is 1 for
+                        * 1st ant
+                        */
+                       control->antenna_sel_tx = (*iterator.this_arg) + 1;
+                       break;
+
+               case IEEE80211_RADIOTAP_DBM_TX_POWER:
+                       control->power_level = *iterator.this_arg;
+                       break;
+
+               case IEEE80211_RADIOTAP_FLAGS:
+                       if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+                               /*
+                                * this indicates that the skb we have been
+                                * handed has the 32-bit FCS CRC at the end...
+                                * we should react to that by snipping it off
+                                * because it will be recomputed and added
+                                * on transmission
+                                */
+                               if (skb->len < (iterator.max_length + FCS_LEN))
+                                       return TXRX_DROP;
+
+                               skb_trim(skb, skb->len - FCS_LEN);
+                       }
+                       if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
+                               control->flags &=
+                                       ~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+                       if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
+                               tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+                       break;
+
+               /*
+                * Please update the file
+                * Documentation/networking/mac80211-injection.txt
+                * when parsing new fields here.
+                */
+
+               default:
+                       break;
+               }
+       }
+
+       if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+               return TXRX_DROP;
+
+       /*
+        * remove the radiotap header
+        * iterator->max_length was sanity-checked against
+        * skb->len by iterator init
+        */
+       skb_pull(skb, iterator.max_length);
+
+       return TXRX_CONTINUE;
+}
+
+/*
+ * initialises @tx
+ */
+static ieee80211_txrx_result
+__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+                      struct sk_buff *skb,
+                      struct net_device *dev,
+                      struct ieee80211_tx_control *control)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_sub_if_data *sdata;
+       ieee80211_txrx_result res = TXRX_CONTINUE;
+
+       int hdrlen;
+
+       memset(tx, 0, sizeof(*tx));
+       tx->skb = skb;
+       tx->dev = dev; /* use original interface */
+       tx->local = local;
+       tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       tx->u.tx.control = control;
+       /*
+        * Set this flag (used below to indicate "automatic fragmentation"),
+        * it will be cleared/left by radiotap as desired.
+        */
+       tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+
+       /* process and remove the injection radiotap header */
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
+               if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP)
+                       return TXRX_DROP;
+
+               /*
+                * __ieee80211_parse_tx_radiotap has now removed
+                * the radiotap header that was present and pre-filled
+                * 'tx' with tx control information.
+                */
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       tx->sta = sta_info_get(local, hdr->addr1);
+       tx->fc = le16_to_cpu(hdr->frame_control);
+
+       if (is_multicast_ether_addr(hdr->addr1)) {
+               tx->flags &= ~IEEE80211_TXRXD_TXUNICAST;
+               control->flags |= IEEE80211_TXCTL_NO_ACK;
+       } else {
+               tx->flags |= IEEE80211_TXRXD_TXUNICAST;
+               control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+       }
+
+       if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
+               if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+                   skb->len + FCS_LEN > local->fragmentation_threshold &&
+                   !local->ops->set_frag_threshold)
+                       tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+               else
+                       tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+       }
+
+       if (!tx->sta)
+               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+       else if (tx->sta->clear_dst_mask) {
+               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+               tx->sta->clear_dst_mask = 0;
+       }
+
+       hdrlen = ieee80211_get_hdrlen(tx->fc);
+       if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
+               u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
+               tx->ethertype = (pos[0] << 8) | pos[1];
+       }
+       control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+
+       return res;
+}
+
+/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
+ * finished with it.
+ *
+ * NB: @tx is uninitialised when passed in here
+ */
+static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+                               struct sk_buff *skb,
+                               struct net_device *mdev,
+                               struct ieee80211_tx_control *control)
+{
+       struct ieee80211_tx_packet_data *pkt_data;
+       struct net_device *dev;
+
+       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+       dev = dev_get_by_index(pkt_data->ifindex);
+       if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+               dev_put(dev);
+               dev = NULL;
+       }
+       if (unlikely(!dev))
+               return -ENODEV;
+       /* initialises tx with control */
+       __ieee80211_tx_prepare(tx, skb, dev, control);
+       return 0;
+}
+
+static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
+                         struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_tx_control *control = tx->u.tx.control;
+       int ret, i;
+
+       if (!ieee80211_qdisc_installed(local->mdev) &&
+           __ieee80211_queue_stopped(local, 0)) {
+               netif_stop_queue(local->mdev);
+               return IEEE80211_TX_AGAIN;
+       }
+       if (skb) {
+               ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
+                                    "TX to low-level driver", skb);
+               ret = local->ops->tx(local_to_hw(local), skb, control);
+               if (ret)
+                       return IEEE80211_TX_AGAIN;
+               local->mdev->trans_start = jiffies;
+               ieee80211_led_tx(local, 1);
+       }
+       if (tx->u.tx.extra_frag) {
+               control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+                                   IEEE80211_TXCTL_USE_CTS_PROTECT |
+                                   IEEE80211_TXCTL_CLEAR_DST_MASK |
+                                   IEEE80211_TXCTL_FIRST_FRAGMENT);
+               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+                       if (!tx->u.tx.extra_frag[i])
+                               continue;
+                       if (__ieee80211_queue_stopped(local, control->queue))
+                               return IEEE80211_TX_FRAG_AGAIN;
+                       if (i == tx->u.tx.num_extra_frag) {
+                               control->tx_rate = tx->u.tx.last_frag_hwrate;
+                               control->rate = tx->u.tx.last_frag_rate;
+                               if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG)
+                                       control->flags |=
+                                               IEEE80211_TXCTL_RATE_CTRL_PROBE;
+                               else
+                                       control->flags &=
+                                               ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+                       }
+
+                       ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
+                                            "TX to low-level driver",
+                                            tx->u.tx.extra_frag[i]);
+                       ret = local->ops->tx(local_to_hw(local),
+                                           tx->u.tx.extra_frag[i],
+                                           control);
+                       if (ret)
+                               return IEEE80211_TX_FRAG_AGAIN;
+                       local->mdev->trans_start = jiffies;
+                       ieee80211_led_tx(local, 1);
+                       tx->u.tx.extra_frag[i] = NULL;
+               }
+               kfree(tx->u.tx.extra_frag);
+               tx->u.tx.extra_frag = NULL;
+       }
+       return IEEE80211_TX_OK;
+}
+
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
+                       struct ieee80211_tx_control *control)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       ieee80211_tx_handler *handler;
+       struct ieee80211_txrx_data tx;
+       ieee80211_txrx_result res = TXRX_DROP, res_prepare;
+       int ret, i;
+
+       WARN_ON(__ieee80211_queue_pending(local, control->queue));
+
+       if (unlikely(skb->len < 10)) {
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       /* initialises tx */
+       res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+
+       if (res_prepare == TXRX_DROP) {
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       /*
+        * key references are protected using RCU and this requires that
+        * we are in a read-site RCU section during receive processing
+        */
+       rcu_read_lock();
+
+       sta = tx.sta;
+       tx.u.tx.mode = local->hw.conf.mode;
+
+       for (handler = local->tx_handlers; *handler != NULL;
+            handler++) {
+               res = (*handler)(&tx);
+               if (res != TXRX_CONTINUE)
+                       break;
+       }
+
+       skb = tx.skb; /* handlers are allowed to change skb */
+
+       if (sta)
+               sta_info_put(sta);
+
+       if (unlikely(res == TXRX_DROP)) {
+               I802_DEBUG_INC(local->tx_handlers_drop);
+               goto drop;
+       }
+
+       if (unlikely(res == TXRX_QUEUED)) {
+               I802_DEBUG_INC(local->tx_handlers_queued);
+               rcu_read_unlock();
+               return 0;
+       }
+
+       if (tx.u.tx.extra_frag) {
+               for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
+                       int next_len, dur;
+                       struct ieee80211_hdr *hdr =
+                               (struct ieee80211_hdr *)
+                               tx.u.tx.extra_frag[i]->data;
+
+                       if (i + 1 < tx.u.tx.num_extra_frag) {
+                               next_len = tx.u.tx.extra_frag[i + 1]->len;
+                       } else {
+                               next_len = 0;
+                               tx.u.tx.rate = tx.u.tx.last_frag_rate;
+                               tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
+                       }
+                       dur = ieee80211_duration(&tx, 0, next_len);
+                       hdr->duration_id = cpu_to_le16(dur);
+               }
+       }
+
+retry:
+       ret = __ieee80211_tx(local, skb, &tx);
+       if (ret) {
+               struct ieee80211_tx_stored_packet *store =
+                       &local->pending_packet[control->queue];
+
+               if (ret == IEEE80211_TX_FRAG_AGAIN)
+                       skb = NULL;
+               set_bit(IEEE80211_LINK_STATE_PENDING,
+                       &local->state[control->queue]);
+               smp_mb();
+               /* When the driver gets out of buffers during sending of
+                * fragments and calls ieee80211_stop_queue, there is
+                * a small window between IEEE80211_LINK_STATE_XOFF and
+                * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+                * gets available in that window (i.e. driver calls
+                * ieee80211_wake_queue), we would end up with ieee80211_tx
+                * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+                * continuing transmitting here when that situation is
+                * possible to have happened. */
+               if (!__ieee80211_queue_stopped(local, control->queue)) {
+                       clear_bit(IEEE80211_LINK_STATE_PENDING,
+                                 &local->state[control->queue]);
+                       goto retry;
+               }
+               memcpy(&store->control, control,
+                      sizeof(struct ieee80211_tx_control));
+               store->skb = skb;
+               store->extra_frag = tx.u.tx.extra_frag;
+               store->num_extra_frag = tx.u.tx.num_extra_frag;
+               store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
+               store->last_frag_rate = tx.u.tx.last_frag_rate;
+               store->last_frag_rate_ctrl_probe =
+                       !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
+       }
+       rcu_read_unlock();
+       return 0;
+
+ drop:
+       if (skb)
+               dev_kfree_skb(skb);
+       for (i = 0; i < tx.u.tx.num_extra_frag; i++)
+               if (tx.u.tx.extra_frag[i])
+                       dev_kfree_skb(tx.u.tx.extra_frag[i]);
+       kfree(tx.u.tx.extra_frag);
+       rcu_read_unlock();
+       return 0;
+}
+
+/* device xmit handlers */
+
+int ieee80211_master_start_xmit(struct sk_buff *skb,
+                               struct net_device *dev)
+{
+       struct ieee80211_tx_control control;
+       struct ieee80211_tx_packet_data *pkt_data;
+       struct net_device *odev = NULL;
+       struct ieee80211_sub_if_data *osdata;
+       int headroom;
+       int ret;
+
+       /*
+        * copy control out of the skb so other people can use skb->cb
+        */
+       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+       memset(&control, 0, sizeof(struct ieee80211_tx_control));
+
+       if (pkt_data->ifindex)
+               odev = dev_get_by_index(pkt_data->ifindex);
+       if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+               dev_put(odev);
+               odev = NULL;
+       }
+       if (unlikely(!odev)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
+                      "originating device\n", dev->name);
+#endif
+               dev_kfree_skb(skb);
+               return 0;
+       }
+       osdata = IEEE80211_DEV_TO_SUB_IF(odev);
+
+       headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
+       if (skb_headroom(skb) < headroom) {
+               if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
+                       dev_kfree_skb(skb);
+                       dev_put(odev);
+                       return 0;
+               }
+       }
+
+       control.ifindex = odev->ifindex;
+       control.type = osdata->type;
+       if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS)
+               control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
+       if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT)
+               control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+       if (pkt_data->flags & IEEE80211_TXPD_REQUEUE)
+               control.flags |= IEEE80211_TXCTL_REQUEUE;
+       control.queue = pkt_data->queue;
+
+       ret = ieee80211_tx(odev, skb, &control);
+       dev_put(odev);
+
+       return ret;
+}
+
+int ieee80211_monitor_start_xmit(struct sk_buff *skb,
+                                struct net_device *dev)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_radiotap_header *prthdr =
+               (struct ieee80211_radiotap_header *)skb->data;
+       u16 len_rthdr;
+
+       /* check for not even having the fixed radiotap header part */
+       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+               goto fail; /* too short to be possibly valid */
+
+       /* is it a header version we can trust to find length from? */
+       if (unlikely(prthdr->it_version))
+               goto fail; /* only version 0 is supported */
+
+       /* then there must be a radiotap header with a length we can use */
+       len_rthdr = ieee80211_get_radiotap_len(skb->data);
+
+       /* does the skb contain enough to deliver on the alleged length? */
+       if (unlikely(skb->len < len_rthdr))
+               goto fail; /* skb too short for claimed rt header extent */
+
+       skb->dev = local->mdev;
+
+       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+       memset(pkt_data, 0, sizeof(*pkt_data));
+       /* needed because we set skb device to master */
+       pkt_data->ifindex = dev->ifindex;
+
+       pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+
+       /*
+        * fix up the pointers accounting for the radiotap
+        * header still being in there.  We are being given
+        * a precooked IEEE80211 header so no need for
+        * normal processing
+        */
+       skb_set_mac_header(skb, len_rthdr);
+       /*
+        * these are just fixed to the end of the rt area since we
+        * don't have any better information and at this point, nobody cares
+        */
+       skb_set_network_header(skb, len_rthdr);
+       skb_set_transport_header(skb, len_rthdr);
+
+       /* pass the radiotap header up to the next stage intact */
+       dev_queue_xmit(skb);
+       return NETDEV_TX_OK;
+
+fail:
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK; /* meaning, we dealt with the skb */
+}
+
+/**
+ * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
+ * subinterfaces (wlan#, WDS, and VLAN interfaces)
+ * @skb: packet to be sent
+ * @dev: incoming interface
+ *
+ * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
+ * not be freed, and caller is responsible for either retrying later or freeing
+ * skb).
+ *
+ * This function takes in an Ethernet header and encapsulates it with suitable
+ * IEEE 802.11 header based on which interface the packet is coming in. The
+ * encapsulated packet will then be passed to master interface, wlan#.11, for
+ * transmission (through low-level driver).
+ */
+int ieee80211_subif_start_xmit(struct sk_buff *skb,
+                              struct net_device *dev)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_sub_if_data *sdata;
+       int ret = 1, head_need;
+       u16 ethertype, hdrlen, fc;
+       struct ieee80211_hdr hdr;
+       const u8 *encaps_data;
+       int encaps_len, skip_header_bytes;
+       int nh_pos, h_pos;
+       struct sta_info *sta;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (unlikely(skb->len < ETH_HLEN)) {
+               printk(KERN_DEBUG "%s: short skb (len=%d)\n",
+                      dev->name, skb->len);
+               ret = 0;
+               goto fail;
+       }
+
+       nh_pos = skb_network_header(skb) - skb->data;
+       h_pos = skb_transport_header(skb) - skb->data;
+
+       /* convert Ethernet header to proper 802.11 header (based on
+        * operation mode) */
+       ethertype = (skb->data[12] << 8) | skb->data[13];
+       /* TODO: handling for 802.1x authorized/unauthorized port */
+       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_AP:
+       case IEEE80211_IF_TYPE_VLAN:
+               fc |= IEEE80211_FCTL_FROMDS;
+               /* DA BSSID SA */
+               memcpy(hdr.addr1, skb->data, ETH_ALEN);
+               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+               hdrlen = 24;
+               break;
+       case IEEE80211_IF_TYPE_WDS:
+               fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+               /* RA TA DA SA */
+               memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
+               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr3, skb->data, ETH_ALEN);
+               memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+               hdrlen = 30;
+               break;
+       case IEEE80211_IF_TYPE_STA:
+               fc |= IEEE80211_FCTL_TODS;
+               /* BSSID SA DA */
+               memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
+               memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               memcpy(hdr.addr3, skb->data, ETH_ALEN);
+               hdrlen = 24;
+               break;
+       case IEEE80211_IF_TYPE_IBSS:
+               /* DA SA BSSID */
+               memcpy(hdr.addr1, skb->data, ETH_ALEN);
+               memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
+               hdrlen = 24;
+               break;
+       default:
+               ret = 0;
+               goto fail;
+       }
+
+       /* receiver is QoS enabled, use a QoS type frame */
+       sta = sta_info_get(local, hdr.addr1);
+       if (sta) {
+               if (sta->flags & WLAN_STA_WME) {
+                       fc |= IEEE80211_STYPE_QOS_DATA;
+                       hdrlen += 2;
+               }
+               sta_info_put(sta);
+       }
+
+       hdr.frame_control = cpu_to_le16(fc);
+       hdr.duration_id = 0;
+       hdr.seq_ctrl = 0;
+
+       skip_header_bytes = ETH_HLEN;
+       if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+               encaps_data = bridge_tunnel_header;
+               encaps_len = sizeof(bridge_tunnel_header);
+               skip_header_bytes -= 2;
+       } else if (ethertype >= 0x600) {
+               encaps_data = rfc1042_header;
+               encaps_len = sizeof(rfc1042_header);
+               skip_header_bytes -= 2;
+       } else {
+               encaps_data = NULL;
+               encaps_len = 0;
+       }
+
+       skb_pull(skb, skip_header_bytes);
+       nh_pos -= skip_header_bytes;
+       h_pos -= skip_header_bytes;
+
+       /* TODO: implement support for fragments so that there is no need to
+        * reallocate and copy payload; it might be enough to support one
+        * extra fragment that would be copied in the beginning of the frame
+        * data.. anyway, it would be nice to include this into skb structure
+        * somehow
+        *
+        * There are few options for this:
+        * use skb->cb as an extra space for 802.11 header
+        * allocate new buffer if not enough headroom
+        * make sure that there is enough headroom in every skb by increasing
+        * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
+        * alloc_skb() (net/core/skbuff.c)
+        */
+       head_need = hdrlen + encaps_len + local->tx_headroom;
+       head_need -= skb_headroom(skb);
+
+       /* We are going to modify skb data, so make a copy of it if happens to
+        * be cloned. This could happen, e.g., with Linux bridge code passing
+        * us broadcast frames. */
+
+       if (head_need > 0 || skb_cloned(skb)) {
+#if 0
+               printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
+                      "of headroom\n", dev->name, head_need);
+#endif
+
+               if (skb_cloned(skb))
+                       I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+               else
+                       I802_DEBUG_INC(local->tx_expand_skb_head);
+               /* Since we have to reallocate the buffer, make sure that there
+                * is enough room for possible WEP IV/ICV and TKIP (8 bytes
+                * before payload and 12 after). */
+               if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
+                                    12, GFP_ATOMIC)) {
+                       printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
+                              "\n", dev->name);
+                       goto fail;
+               }
+       }
+
+       if (encaps_data) {
+               memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+               nh_pos += encaps_len;
+               h_pos += encaps_len;
+       }
+
+       if (fc & IEEE80211_STYPE_QOS_DATA) {
+               __le16 *qos_control;
+
+               qos_control = (__le16*) skb_push(skb, 2);
+               memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
+               /*
+                * Maybe we could actually set some fields here, for now just
+                * initialise to zero to indicate no special operation.
+                */
+               *qos_control = 0;
+       } else
+               memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+
+       nh_pos += hdrlen;
+       h_pos += hdrlen;
+
+       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+       pkt_data->ifindex = dev->ifindex;
+
+       skb->dev = local->mdev;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       /* Update skb pointers to various headers since this modified frame
+        * is going to go through Linux networking code that may potentially
+        * need things like pointer to IP header. */
+       skb_set_mac_header(skb, 0);
+       skb_set_network_header(skb, nh_pos);
+       skb_set_transport_header(skb, h_pos);
+
+       dev->trans_start = jiffies;
+       dev_queue_xmit(skb);
+
+       return 0;
+
+ fail:
+       if (!ret)
+               dev_kfree_skb(skb);
+
+       return ret;
+}
+
+/*
+ * This is the transmit routine for the 802.11 type interfaces
+ * called by upper layers of the linux networking
+ * stack when it has a frame to transmit
+ */
+int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (skb->len < 10) {
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       if (skb_headroom(skb) < sdata->local->tx_headroom) {
+               if (pskb_expand_head(skb, sdata->local->tx_headroom,
+                                    0, GFP_ATOMIC)) {
+                       dev_kfree_skb(skb);
+                       return 0;
+               }
+       }
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
+
+       pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+       pkt_data->ifindex = sdata->dev->ifindex;
+
+       skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
+       skb->dev = sdata->local->mdev;
+
+       /*
+        * We're using the protocol field of the the frame control header
+        * to request TX callback for hostapd. BIT(1) is checked.
+        */
+       if ((fc & BIT(1)) == BIT(1)) {
+               pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
+               fc &= ~BIT(1);
+               hdr->frame_control = cpu_to_le16(fc);
+       }
+
+       if (!(fc & IEEE80211_FCTL_PROTECTED))
+               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       dev_queue_xmit(skb);
+
+       return 0;
+}
+
+/* helper functions for pending packets for when queues are stopped */
+
+void ieee80211_clear_tx_pending(struct ieee80211_local *local)
+{
+       int i, j;
+       struct ieee80211_tx_stored_packet *store;
+
+       for (i = 0; i < local->hw.queues; i++) {
+               if (!__ieee80211_queue_pending(local, i))
+                       continue;
+               store = &local->pending_packet[i];
+               kfree_skb(store->skb);
+               for (j = 0; j < store->num_extra_frag; j++)
+                       kfree_skb(store->extra_frag[j]);
+               kfree(store->extra_frag);
+               clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+       }
+}
+
+void ieee80211_tx_pending(unsigned long data)
+{
+       struct ieee80211_local *local = (struct ieee80211_local *)data;
+       struct net_device *dev = local->mdev;
+       struct ieee80211_tx_stored_packet *store;
+       struct ieee80211_txrx_data tx;
+       int i, ret, reschedule = 0;
+
+       netif_tx_lock_bh(dev);
+       for (i = 0; i < local->hw.queues; i++) {
+               if (__ieee80211_queue_stopped(local, i))
+                       continue;
+               if (!__ieee80211_queue_pending(local, i)) {
+                       reschedule = 1;
+                       continue;
+               }
+               store = &local->pending_packet[i];
+               tx.u.tx.control = &store->control;
+               tx.u.tx.extra_frag = store->extra_frag;
+               tx.u.tx.num_extra_frag = store->num_extra_frag;
+               tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
+               tx.u.tx.last_frag_rate = store->last_frag_rate;
+               tx.flags = 0;
+               if (store->last_frag_rate_ctrl_probe)
+                       tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+               ret = __ieee80211_tx(local, store->skb, &tx);
+               if (ret) {
+                       if (ret == IEEE80211_TX_FRAG_AGAIN)
+                               store->skb = NULL;
+               } else {
+                       clear_bit(IEEE80211_LINK_STATE_PENDING,
+                                 &local->state[i]);
+                       reschedule = 1;
+               }
+       }
+       netif_tx_unlock_bh(dev);
+       if (reschedule) {
+               if (!ieee80211_qdisc_installed(dev)) {
+                       if (!__ieee80211_queue_stopped(local, 0))
+                               netif_wake_queue(dev);
+               } else
+                       netif_schedule(dev);
+       }
+}
+
+/* functions for drivers to get certain frames */
+
+static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
+                                    struct ieee80211_if_ap *bss,
+                                    struct sk_buff *skb)
+{
+       u8 *pos, *tim;
+       int aid0 = 0;
+       int i, have_bits = 0, n1, n2;
+
+       /* Generate bitmap for TIM only if there are any STAs in power save
+        * mode. */
+       read_lock_bh(&local->sta_lock);
+       if (atomic_read(&bss->num_sta_ps) > 0)
+               /* in the hope that this is faster than
+                * checking byte-for-byte */
+               have_bits = !bitmap_empty((unsigned long*)bss->tim,
+                                         IEEE80211_MAX_AID+1);
+
+       if (bss->dtim_count == 0)
+               bss->dtim_count = bss->dtim_period - 1;
+       else
+               bss->dtim_count--;
+
+       tim = pos = (u8 *) skb_put(skb, 6);
+       *pos++ = WLAN_EID_TIM;
+       *pos++ = 4;
+       *pos++ = bss->dtim_count;
+       *pos++ = bss->dtim_period;
+
+       if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
+               aid0 = 1;
+
+       if (have_bits) {
+               /* Find largest even number N1 so that bits numbered 1 through
+                * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
+                * (N2 + 1) x 8 through 2007 are 0. */
+               n1 = 0;
+               for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
+                       if (bss->tim[i]) {
+                               n1 = i & 0xfe;
+                               break;
+                       }
+               }
+               n2 = n1;
+               for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
+                       if (bss->tim[i]) {
+                               n2 = i;
+                               break;
+                       }
+               }
+
+               /* Bitmap control */
+               *pos++ = n1 | aid0;
+               /* Part Virt Bitmap */
+               memcpy(pos, bss->tim + n1, n2 - n1 + 1);
+
+               tim[1] = n2 - n1 + 4;
+               skb_put(skb, n2 - n1);
+       } else {
+               *pos++ = aid0; /* Bitmap control */
+               *pos++ = 0; /* Part Virt Bitmap */
+       }
+       read_unlock_bh(&local->sta_lock);
+}
+
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
+                                    struct ieee80211_tx_control *control)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sk_buff *skb;
+       struct net_device *bdev;
+       struct ieee80211_sub_if_data *sdata = NULL;
+       struct ieee80211_if_ap *ap = NULL;
+       struct ieee80211_rate *rate;
+       struct rate_control_extra extra;
+       u8 *b_head, *b_tail;
+       int bh_len, bt_len;
+
+       bdev = dev_get_by_index(if_id);
+       if (bdev) {
+               sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+               ap = &sdata->u.ap;
+               dev_put(bdev);
+       }
+
+       if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
+           !ap->beacon_head) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "no beacon data avail for idx=%d "
+                              "(%s)\n", if_id, bdev ? bdev->name : "N/A");
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+               return NULL;
+       }
+
+       /* Assume we are generating the normal beacon locally */
+       b_head = ap->beacon_head;
+       b_tail = ap->beacon_tail;
+       bh_len = ap->beacon_head_len;
+       bt_len = ap->beacon_tail_len;
+
+       skb = dev_alloc_skb(local->tx_headroom +
+               bh_len + bt_len + 256 /* maximum TIM len */);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, local->tx_headroom);
+       memcpy(skb_put(skb, bh_len), b_head, bh_len);
+
+       ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
+
+       ieee80211_beacon_add_tim(local, ap, skb);
+
+       if (b_tail) {
+               memcpy(skb_put(skb, bt_len), b_tail, bt_len);
+       }
+
+       if (control) {
+               memset(&extra, 0, sizeof(extra));
+               extra.mode = local->oper_hw_mode;
+
+               rate = rate_control_get_rate(local, local->mdev, skb, &extra);
+               if (!rate) {
+                       if (net_ratelimit()) {
+                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
+                                      "found\n", wiphy_name(local->hw.wiphy));
+                       }
+                       dev_kfree_skb(skb);
+                       return NULL;
+               }
+
+               control->tx_rate =
+                       ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
+                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+                       rate->val2 : rate->val;
+               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+               control->power_level = local->hw.conf.power_level;
+               control->flags |= IEEE80211_TXCTL_NO_ACK;
+               control->retry_limit = 1;
+               control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+       }
+
+       ap->num_beacons++;
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_beacon_get);
+
+void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
+                      const void *frame, size_t frame_len,
+                      const struct ieee80211_tx_control *frame_txctl,
+                      struct ieee80211_rts *rts)
+{
+       const struct ieee80211_hdr *hdr = frame;
+       u16 fctl;
+
+       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
+       rts->frame_control = cpu_to_le16(fctl);
+       rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl);
+       memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
+       memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
+}
+EXPORT_SYMBOL(ieee80211_rts_get);
+
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
+                            const void *frame, size_t frame_len,
+                            const struct ieee80211_tx_control *frame_txctl,
+                            struct ieee80211_cts *cts)
+{
+       const struct ieee80211_hdr *hdr = frame;
+       u16 fctl;
+
+       fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
+       cts->frame_control = cpu_to_le16(fctl);
+       cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl);
+       memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_get);
+
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+                         struct ieee80211_tx_control *control)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sk_buff *skb;
+       struct sta_info *sta;
+       ieee80211_tx_handler *handler;
+       struct ieee80211_txrx_data tx;
+       ieee80211_txrx_result res = TXRX_DROP;
+       struct net_device *bdev;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_ap *bss = NULL;
+
+       bdev = dev_get_by_index(if_id);
+       if (bdev) {
+               sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+               bss = &sdata->u.ap;
+               dev_put(bdev);
+       }
+       if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
+               return NULL;
+
+       if (bss->dtim_count != 0)
+               return NULL; /* send buffered bc/mc only after DTIM beacon */
+       memset(control, 0, sizeof(*control));
+       while (1) {
+               skb = skb_dequeue(&bss->ps_bc_buf);
+               if (!skb)
+                       return NULL;
+               local->total_ps_buffered--;
+
+               if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
+                       struct ieee80211_hdr *hdr =
+                               (struct ieee80211_hdr *) skb->data;
+                       /* more buffered multicast/broadcast frames ==> set
+                        * MoreData flag in IEEE 802.11 header to inform PS
+                        * STAs */
+                       hdr->frame_control |=
+                               cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+               }
+
+               if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control))
+                       break;
+               dev_kfree_skb_any(skb);
+       }
+       sta = tx.sta;
+       tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
+       tx.u.tx.mode = local->hw.conf.mode;
+
+       for (handler = local->tx_handlers; *handler != NULL; handler++) {
+               res = (*handler)(&tx);
+               if (res == TXRX_DROP || res == TXRX_QUEUED)
+                       break;
+       }
+       dev_put(tx.dev);
+       skb = tx.skb; /* handlers are allowed to change skb */
+
+       if (res == TXRX_DROP) {
+               I802_DEBUG_INC(local->tx_handlers_drop);
+               dev_kfree_skb(skb);
+               skb = NULL;
+       } else if (res == TXRX_QUEUED) {
+               I802_DEBUG_INC(local->tx_handlers_queued);
+               skb = NULL;
+       }
+
+       if (sta)
+               sta_info_put(sta);
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_get_buffered_bc);
diff --git a/package/mac80211/src/mac80211/util.c b/package/mac80211/src/mac80211/util.c
new file mode 100644 (file)
index 0000000..27203f1
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * utilities for mac80211
+ */
+
+#include <net/mac80211.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitmap.h>
+#include <net/cfg80211.h>
+
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "wme.h"
+
+/* privid for wiphys to determine whether they belong to us or not */
+void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+const unsigned char rfc1042_header[] =
+       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+const unsigned char bridge_tunnel_header[] =
+       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+
+/* No encapsulation header if EtherType < 0x600 (=length) */
+static const unsigned char eapol_header[] =
+       { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+
+
+static int rate_list_match(const int *rate_list, int rate)
+{
+       int i;
+
+       if (!rate_list)
+               return 0;
+
+       for (i = 0; rate_list[i] >= 0; i++)
+               if (rate_list[i] == rate)
+                       return 1;
+
+       return 0;
+}
+
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+                            struct ieee80211_hw_mode *mode)
+{
+       int i;
+
+       for (i = 0; i < mode->num_rates; i++) {
+               struct ieee80211_rate *rate = &mode->rates[i];
+
+               rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
+                                IEEE80211_RATE_BASIC);
+
+               if (local->supp_rates[mode->mode]) {
+                       if (!rate_list_match(local->supp_rates[mode->mode],
+                                            rate->rate))
+                               continue;
+               }
+
+               rate->flags |= IEEE80211_RATE_SUPPORTED;
+
+               /* Use configured basic rate set if it is available. If not,
+                * use defaults that are sane for most cases. */
+               if (local->basic_rates[mode->mode]) {
+                       if (rate_list_match(local->basic_rates[mode->mode],
+                                           rate->rate))
+                               rate->flags |= IEEE80211_RATE_BASIC;
+               } else switch (mode->mode) {
+               case MODE_IEEE80211A:
+                       if (rate->rate == 60 || rate->rate == 120 ||
+                           rate->rate == 240)
+                               rate->flags |= IEEE80211_RATE_BASIC;
+                       break;
+               case MODE_IEEE80211B:
+                       if (rate->rate == 10 || rate->rate == 20)
+                               rate->flags |= IEEE80211_RATE_BASIC;
+                       break;
+               case MODE_IEEE80211G:
+                       if (rate->rate == 10 || rate->rate == 20 ||
+                           rate->rate == 55 || rate->rate == 110)
+                               rate->flags |= IEEE80211_RATE_BASIC;
+                       break;
+               case NUM_IEEE80211_MODES:
+                       /* not useful */
+                       break;
+               }
+
+               /* Set ERP and MANDATORY flags based on phymode */
+               switch (mode->mode) {
+               case MODE_IEEE80211A:
+                       if (rate->rate == 60 || rate->rate == 120 ||
+                           rate->rate == 240)
+                               rate->flags |= IEEE80211_RATE_MANDATORY;
+                       break;
+               case MODE_IEEE80211B:
+                       if (rate->rate == 10)
+                               rate->flags |= IEEE80211_RATE_MANDATORY;
+                       break;
+               case MODE_IEEE80211G:
+                       if (rate->rate == 10 || rate->rate == 20 ||
+                           rate->rate == 55 || rate->rate == 110 ||
+                           rate->rate == 60 || rate->rate == 120 ||
+                           rate->rate == 240)
+                               rate->flags |= IEEE80211_RATE_MANDATORY;
+                       break;
+               case NUM_IEEE80211_MODES:
+                       /* not useful */
+                       break;
+               }
+               if (ieee80211_is_erp_rate(mode->mode, rate->rate))
+                       rate->flags |= IEEE80211_RATE_ERP;
+       }
+}
+
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+{
+       u16 fc;
+
+       if (len < 24)
+               return NULL;
+
+       fc = le16_to_cpu(hdr->frame_control);
+
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_DATA:
+               switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+               case IEEE80211_FCTL_TODS:
+                       return hdr->addr1;
+               case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+                       return NULL;
+               case IEEE80211_FCTL_FROMDS:
+                       return hdr->addr2;
+               case 0:
+                       return hdr->addr3;
+               }
+               break;
+       case IEEE80211_FTYPE_MGMT:
+               return hdr->addr3;
+       case IEEE80211_FTYPE_CTL:
+               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
+                       return hdr->addr1;
+               else
+                       return NULL;
+       }
+
+       return NULL;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+       int hdrlen = 24;
+
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+                       hdrlen = 30; /* Addr4 */
+               /*
+                * The QoS Control field is two bytes and its presence is
+                * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
+                * hdrlen if that bit is set.
+                * This works by masking out the bit and shifting it to
+                * bit position 1 so the result has the value 0 or 2.
+                */
+               hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
+                               >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
+               break;
+       case IEEE80211_FTYPE_CTL:
+               /*
+                * ACK and CTS are 10 bytes, all others 16. To see how
+                * to get this condition consider
+                *   subtype mask:   0b0000000011110000 (0x00F0)
+                *   ACK subtype:    0b0000000011010000 (0x00D0)
+                *   CTS subtype:    0b0000000011000000 (0x00C0)
+                *   bits that matter:         ^^^      (0x00E0)
+                *   value of those: 0b0000000011000000 (0x00C0)
+                */
+               if ((fc & 0xE0) == 0xC0)
+                       hdrlen = 10;
+               else
+                       hdrlen = 16;
+               break;
+       }
+
+       return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen);
+
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+{
+       const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
+       int hdrlen;
+
+       if (unlikely(skb->len < 10))
+               return 0;
+       hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+       if (unlikely(hdrlen > skb->len))
+               return 0;
+       return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+
+int ieee80211_is_eapol(const struct sk_buff *skb)
+{
+       const struct ieee80211_hdr *hdr;
+       u16 fc;
+       int hdrlen;
+
+       if (unlikely(skb->len < 10))
+               return 0;
+
+       hdr = (const struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
+
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return 0;
+
+       hdrlen = ieee80211_get_hdrlen(fc);
+
+       if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
+                    memcmp(skb->data + hdrlen, eapol_header,
+                           sizeof(eapol_header)) == 0))
+               return 1;
+
+       return 0;
+}
+
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+
+       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+       if (tx->u.tx.extra_frag) {
+               struct ieee80211_hdr *fhdr;
+               int i;
+               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+                       fhdr = (struct ieee80211_hdr *)
+                               tx->u.tx.extra_frag[i]->data;
+                       fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+               }
+       }
+}
+
+int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+                            int rate, int erp, int short_preamble)
+{
+       int dur;
+
+       /* calculate duration (in microseconds, rounded up to next higher
+        * integer if it includes a fractional microsecond) to send frame of
+        * len bytes (does not include FCS) at the given rate. Duration will
+        * also include SIFS.
+        *
+        * rate is in 100 kbps, so divident is multiplied by 10 in the
+        * DIV_ROUND_UP() operations.
+        */
+
+       if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+               /*
+                * OFDM:
+                *
+                * N_DBPS = DATARATE x 4
+                * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
+                *      (16 = SIGNAL time, 6 = tail bits)
+                * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
+                *
+                * T_SYM = 4 usec
+                * 802.11a - 17.5.2: aSIFSTime = 16 usec
+                * 802.11g - 19.8.4: aSIFSTime = 10 usec +
+                *      signal ext = 6 usec
+                */
+               dur = 16; /* SIFS + signal ext */
+               dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
+               dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+               dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+                                       4 * rate); /* T_SYM x N_SYM */
+       } else {
+               /*
+                * 802.11b or 802.11g with 802.11b compatibility:
+                * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
+                * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
+                *
+                * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
+                * aSIFSTime = 10 usec
+                * aPreambleLength = 144 usec or 72 usec with short preamble
+                * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+                */
+               dur = 10; /* aSIFSTime = 10 usec */
+               dur += short_preamble ? (72 + 24) : (144 + 48);
+
+               dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+       }
+
+       return dur;
+}
+
+/* Exported duration function for driver use */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
+                                       size_t frame_len, int rate)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
+       u16 dur;
+       int erp;
+
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+       erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
+       dur = ieee80211_frame_duration(local, frame_len, rate,
+                      erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
+
+       dev_put(bdev);
+       return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_generic_frame_duration);
+
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
+                             size_t frame_len,
+                             const struct ieee80211_tx_control *frame_txctl)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_rate *rate;
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
+       int short_preamble;
+       int erp;
+       u16 dur;
+
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+       short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
+
+       rate = frame_txctl->rts_rate;
+       erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+       /* CTS duration */
+       dur = ieee80211_frame_duration(local, 10, rate->rate,
+                                      erp, short_preamble);
+       /* Data frame duration */
+       dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+                                       erp, short_preamble);
+       /* ACK duration */
+       dur += ieee80211_frame_duration(local, 10, rate->rate,
+                                       erp, short_preamble);
+
+       dev_put(bdev);
+       return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_rts_duration);
+
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
+                                   size_t frame_len,
+                                   const struct ieee80211_tx_control *frame_txctl)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_rate *rate;
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
+       int short_preamble;
+       int erp;
+       u16 dur;
+
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+       short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
+
+       rate = frame_txctl->rts_rate;
+       erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+       /* Data frame duration */
+       dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+                                      erp, short_preamble);
+       if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+               /* ACK duration */
+               dur += ieee80211_frame_duration(local, 10, rate->rate,
+                                               erp, short_preamble);
+       }
+
+       dev_put(bdev);
+       return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+
+struct ieee80211_rate *
+ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
+{
+       struct ieee80211_hw_mode *mode;
+       int r;
+
+       list_for_each_entry(mode, &local->modes_list, list) {
+               if (mode->mode != phymode)
+                       continue;
+               for (r = 0; r < mode->num_rates; r++) {
+                       struct ieee80211_rate *rate = &mode->rates[r];
+                       if (rate->val == hw_rate ||
+                           (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
+                            rate->val2 == hw_rate))
+                               return rate;
+               }
+       }
+
+       return NULL;
+}
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
+                              &local->state[queue])) {
+               if (test_bit(IEEE80211_LINK_STATE_PENDING,
+                            &local->state[queue]))
+                       tasklet_schedule(&local->tx_pending_tasklet);
+               else
+                       if (!ieee80211_qdisc_installed(local->mdev)) {
+                               if (queue == 0)
+                                       netif_wake_queue(local->mdev);
+                       } else
+                               __netif_schedule(local->mdev);
+       }
+}
+EXPORT_SYMBOL(ieee80211_wake_queue);
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+               netif_stop_queue(local->mdev);
+       set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+EXPORT_SYMBOL(ieee80211_stop_queue);
+
+void ieee80211_start_queues(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       int i;
+
+       for (i = 0; i < local->hw.queues; i++)
+               clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
+       if (!ieee80211_qdisc_installed(local->mdev))
+               netif_start_queue(local->mdev);
+}
+EXPORT_SYMBOL(ieee80211_start_queues);
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+       int i;
+
+       for (i = 0; i < hw->queues; i++)
+               ieee80211_stop_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_stop_queues);
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+       int i;
+
+       for (i = 0; i < hw->queues; i++)
+               ieee80211_wake_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_wake_queues);
index 1ad3d75281cc9e044b80ec97c5d2a56e4050e6aa..6675261e958f41abb0fc23a8bf3f3178e0364c8f 100644 (file)
@@ -63,11 +63,11 @@ static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
 }
 
 
-void ieee80211_wep_get_iv(struct ieee80211_local *local,
-                         struct ieee80211_key *key, u8 *iv)
+static void ieee80211_wep_get_iv(struct ieee80211_local *local,
+                                struct ieee80211_key *key, u8 *iv)
 {
        local->wep_iv++;
-       if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen))
+       if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen))
                local->wep_iv += 0x0100;
 
        if (!iv)
@@ -76,13 +76,13 @@ void ieee80211_wep_get_iv(struct ieee80211_local *local,
        *iv++ = (local->wep_iv >> 16) & 0xff;
        *iv++ = (local->wep_iv >> 8) & 0xff;
        *iv++ = local->wep_iv & 0xff;
-       *iv++ = key->keyidx << 6;
+       *iv++ = key->conf.keyidx << 6;
 }
 
 
-u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
-                         struct sk_buff *skb,
-                         struct ieee80211_key *key)
+static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
+                               struct sk_buff *skb,
+                               struct ieee80211_key *key)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 fc;
@@ -109,9 +109,9 @@ u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
 }
 
 
-void ieee80211_wep_remove_iv(struct ieee80211_local *local,
-                            struct sk_buff *skb,
-                            struct ieee80211_key *key)
+static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
+                                   struct sk_buff *skb,
+                                   struct ieee80211_key *key)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 fc;
@@ -159,10 +159,10 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
        u8 *rc4key, *iv;
        size_t len;
 
-       if (!key || key->alg != ALG_WEP)
+       if (!key || key->conf.alg != ALG_WEP)
                return -1;
 
-       klen = 3 + key->keylen;
+       klen = 3 + key->conf.keylen;
        rc4key = kmalloc(klen, GFP_ATOMIC);
        if (!rc4key)
                return -1;
@@ -179,7 +179,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
        memcpy(rc4key, iv, 3);
 
        /* Copy rest of the WEP key (the secret part) */
-       memcpy(rc4key + 3, key->key, key->keylen);
+       memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
 
        /* Add room for ICV */
        skb_put(skb, WEP_ICV_LEN);
@@ -251,10 +251,10 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 
        keyidx = skb->data[hdrlen + 3] >> 6;
 
-       if (!key || keyidx != key->keyidx || key->alg != ALG_WEP)
+       if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP)
                return -1;
 
-       klen = 3 + key->keylen;
+       klen = 3 + key->conf.keylen;
 
        rc4key = kmalloc(klen, GFP_ATOMIC);
        if (!rc4key)
@@ -264,7 +264,7 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
        memcpy(rc4key, skb->data + hdrlen, 3);
 
        /* Copy rest of the WEP key (the secret part) */
-       memcpy(rc4key + 3, key->key, key->keylen);
+       memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
 
        if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
                                       skb->data + hdrlen + WEP_IV_LEN,
@@ -286,43 +286,99 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 }
 
 
-int ieee80211_wep_get_keyidx(struct sk_buff *skb)
+u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 fc;
        int hdrlen;
+       u8 *ivpos;
+       u32 iv;
 
        fc = le16_to_cpu(hdr->frame_control);
        if (!(fc & IEEE80211_FCTL_PROTECTED))
-               return -1;
+               return NULL;
 
        hdrlen = ieee80211_get_hdrlen(fc);
+       ivpos = skb->data + hdrlen;
+       iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 
-       if (skb->len < 8 + hdrlen)
-               return -1;
+       if (ieee80211_wep_weak_iv(iv, key->conf.keylen))
+               return ivpos;
 
-       return skb->data[hdrlen + 3] >> 6;
+       return NULL;
 }
 
+ieee80211_txrx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
+{
+       if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+           ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+            (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
+               return TXRX_CONTINUE;
+
+       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+               if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
+                                      "failed\n", rx->dev->name);
+                       return TXRX_DROP;
+               }
+       } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
+               ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
+               /* remove ICV */
+               skb_trim(rx->skb, rx->skb->len - 4);
+       }
 
-u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
+       return TXRX_CONTINUE;
+}
+
+static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
+               if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+                       return -1;
+       } else {
+               tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
+               if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
+                       if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
+                               return -1;
+               }
+       }
+       return 0;
+}
+
+ieee80211_txrx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
        u16 fc;
-       int hdrlen;
-       u8 *ivpos;
-       u32 iv;
 
        fc = le16_to_cpu(hdr->frame_control);
-       if (!(fc & IEEE80211_FCTL_PROTECTED))
-               return NULL;
 
-       hdrlen = ieee80211_get_hdrlen(fc);
-       ivpos = skb->data + hdrlen;
-       iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
+       if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+            ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+             (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
+               return TXRX_CONTINUE;
 
-       if (ieee80211_wep_weak_iv(iv, key->keylen))
-               return ivpos;
+       tx->u.tx.control->iv_len = WEP_IV_LEN;
+       tx->u.tx.control->icv_len = WEP_ICV_LEN;
+       ieee80211_tx_set_iswep(tx);
 
-       return NULL;
+       if (wep_encrypt_skb(tx, tx->skb) < 0) {
+               I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
+               return TXRX_DROP;
+       }
+
+       if (tx->u.tx.extra_frag) {
+               int i;
+               for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+                       if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
+                               I802_DEBUG_INC(tx->local->
+                                              tx_handlers_drop_wep);
+                               return TXRX_DROP;
+                       }
+               }
+       }
+
+       return TXRX_CONTINUE;
 }
index bfe29e8e10aac7dfe4447f8034230494dd9ee89b..785fbb4e0dd70d869777b5ecb38d9cbf958ce8f9 100644 (file)
 
 int ieee80211_wep_init(struct ieee80211_local *local);
 void ieee80211_wep_free(struct ieee80211_local *local);
-void ieee80211_wep_get_iv(struct ieee80211_local *local,
-                         struct ieee80211_key *key, u8 *iv);
-u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
-                         struct sk_buff *skb,
-                         struct ieee80211_key *key);
-void ieee80211_wep_remove_iv(struct ieee80211_local *local,
-                            struct sk_buff *skb,
-                            struct ieee80211_key *key);
 void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
                                size_t klen, u8 *data, size_t data_len);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
@@ -34,7 +26,11 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_key *key);
 int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_key *key);
-int ieee80211_wep_get_keyidx(struct sk_buff *skb);
 u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
+ieee80211_txrx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_txrx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
+
 #endif /* WEP_H */
index 9ff35e863285f758af6ca63e4df52980f0937d4e..5b8a157975a35dd452bc6e03e17f5dafcae09788 100644 (file)
 #include "ieee80211_i.h"
 #include "wme.h"
 
-static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
-{
-       return (fc & 0x8C) == 0x88;
-}
-
-
-ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
-{
-       u8 *data = rx->skb->data;
-       int tid;
-       unsigned int is_agg_frame = 0;
-
-       /* does the frame have a qos control field? */
-       if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
-               u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
-
-               /* frame has qos control */
-               rx->u.rx.qos_control = le16_to_cpu(*((__le16*)qc));
-               tid = rx->u.rx.qos_control & QOS_CONTROL_TID_MASK;
-               if (rx->u.rx.qos_control &
-                   IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-                       is_agg_frame = 1;
-       } else {
-               if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
-                       /* Separate TID for management frames */
-                       tid = NUM_RX_DATA_QUEUES - 1;
-               } else {
-                       /* no qos control present */
-                       tid = 0; /* 802.1d - Best Effort */
-               }
-               rx->u.rx.qos_control = 0;
-       }
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-       I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
-       if (rx->sta) {
-               I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-       }
-#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
-
-       rx->u.rx.queue = tid;
-       rx->u.rx.is_agg_frame = is_agg_frame;
-       /* Set skb->priority to 1d tag if highest order bit of TID is not set.
-        * For now, set skb->priority to 0 for other cases. */
-       rx->skb->priority = (tid > 7) ? 0 : tid;
-
-       return TXRX_CONTINUE;
-}
-
-
-ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
-{
-       u16 fc = rx->fc;
-       u8 *data = rx->skb->data;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
-
-       if (!WLAN_FC_IS_QOS_DATA(fc))
-               return TXRX_CONTINUE;
-
-       /* remove the qos control field, update frame type and meta-data */
-       memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
-       hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
-       /* change frame type to non QOS */
-       rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
-       hdr->frame_control = cpu_to_le16(fc);
-
-       return TXRX_CONTINUE;
-}
-
-
-#ifdef CONFIG_NET_SCHED
 /* maximum number of hardware queues we support. */
 #define TC_80211_MAX_QUEUES 8
 
@@ -166,13 +94,9 @@ static inline int wme_downgrade_ac(struct sk_buff *skb)
 static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
 {
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(qd->dev);
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-       struct ieee80211_tx_packet_data *pkt_data =
-               (struct ieee80211_tx_packet_data *) skb->cb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        unsigned short fc = le16_to_cpu(hdr->frame_control);
-       int qos, tsid, dir;
+       int qos;
        const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
        /* see if frame is data or non data frame */
@@ -182,12 +106,8 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
                return IEEE80211_TX_QUEUE_DATA0;
        }
 
-       if (unlikely(pkt_data->mgmt_iface)) {
-               /* Data frames from hostapd (mainly, EAPOL) use AC_VO
-               * and they will include QoS control fields if
-               * the target STA is using WME. */
-               skb->priority = 7;
-               return ieee802_1d_to_ac[skb->priority];
+       if (0 /* injected */) {
+               /* use AC from radiotap */
        }
 
        /* is this a QoS frame? */
@@ -201,34 +121,9 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
        skb->priority = classify_1d(skb, qd);
-       tsid = 8 + skb->priority;
-
-       /* FIXME: only uplink needs to be checked for Tx */
-       dir = STA_TS_UPLINK;
-
-       if ((sdata->type == IEEE80211_IF_TYPE_STA) &&
-           (local->wmm_acm & BIT(skb->priority))) {
-               switch (ifsta->ts_data[tsid][dir].status) {
-               case TS_STATUS_ACTIVE:
-                       /* if TS Management is enabled, update used_time */
-                       ifsta->ts_data[tsid][dir].used_time_usec +=
-                               ifsta->MPDUExchangeTime;
-                       break;
-               case TS_STATUS_THROTTLING:
-                       /* if admitted time is used up, refuse to send more */
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "QoS packet throttling\n");
-                       break;
-               default:
-                       break;
-               }
-       }
 
        /* in case we are a client verify acm is not set for this ac */
-       while ((local->wmm_acm & BIT(skb->priority)) &&
-              !((sdata->type == IEEE80211_IF_TYPE_STA) &&
-                (ifsta->ts_data[skb->priority + EDCA_TSID_MIN][dir].status
-                       == TS_STATUS_ACTIVE))) {
+       while (unlikely(local->wmm_acm & BIT(skb->priority))) {
                if (wme_downgrade_ac(skb)) {
                        /* No AC with lower priority has acm=0, drop packet. */
                        return -1;
@@ -251,7 +146,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
        struct Qdisc *qdisc;
        int err, queue;
 
-       if (pkt_data->requeue) {
+       if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
                skb_queue_tail(&q->requeued[pkt_data->queue], skb);
                qd->q.qlen++;
                return 0;
@@ -458,7 +353,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
                skb_queue_head_init(&q->requeued[i]);
                q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
                                                 qd->handle);
-               if (q->queues[i] == 0) {
+               if (!q->queues[i]) {
                        q->queues[i] = &noop_qdisc;
                        printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i);
                }
@@ -709,4 +604,3 @@ void ieee80211_wme_unregister(void)
 {
        unregister_qdisc(&wme_qdisc_ops);
 }
-#endif /* CONFIG_NET_SCHED */
index f0bff10f0e08676c94c61df8646885973756245d..76c713a6450c37290f0ba521cbe2e212e06bc514 100644 (file)
 
 #define QOS_CONTROL_TAG1D_MASK 0x07
 
-ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx);
-
-ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx);
+static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
+{
+       return (fc & 0x8C) == 0x88;
+}
 
 #ifdef CONFIG_NET_SCHED
 void ieee80211_install_qdisc(struct net_device *dev);
index 280688694b8dda4d0ec88d67b7fa214654942be4..0b32ab64ebdf2f5df7d0db5e31505d2e4389e41d 100644 (file)
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/compiler.h>
-#include <net/iw_handler.h>
-
 #include <net/mac80211.h>
-#include "ieee80211_common.h"
+
 #include "ieee80211_i.h"
 #include "michael.h"
 #include "tkip.h"
 #include "aes_ccm.h"
 #include "wpa.h"
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-#include "hostapd_ioctl.h"
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
 
 static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
                                  u8 *qos_tid, u8 **data, size_t *data_len)
@@ -88,24 +82,16 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 
        fc = tx->fc;
 
-       if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 ||
+       if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
            !WLAN_FC_DATA_PRESENT(fc))
                return TXRX_CONTINUE;
 
        if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
                return TXRX_DROP;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if ((tx->sta && tx->sta->wpa_trigger & WPA_TRIGGER_FAIL_TX_MIC) ||
-           (!tx->u.tx.unicast &&
-            tx->local->wpa_trigger & WPA_TRIGGER_FAIL_TX_MIC)) {
-               wpa_test = 1;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       if (!tx->key->force_sw_encrypt &&
-           !tx->fragmented &&
-           !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) &&
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
            !wpa_test) {
                /* hwaccel - with no need for preallocated room for Michael MIC
                 */
@@ -128,31 +114,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 #else
        authenticator = 1;
 #endif
-       key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
-                           ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
+       key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
+                                ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
        mic = skb_put(skb, MICHAEL_MIC_LEN);
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (tx->sta && tx->sta->wpa_trigger & WPA_TRIGGER_FAIL_TX_MIC) {
-               printk(KERN_INFO "%s: WPA testing - corrupting TX Michael MIC "
-                      "for STA " MAC_FMT "\n",
-                      tx->dev->name, MAC_ARG(tx->sta->addr));
-               tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
-               tx->sta->wpa_trigger &= ~WPA_TRIGGER_FAIL_TX_MIC;
-               tx->wpa_test = 1;
-               mic[0]++;
-       } else if (!tx->u.tx.unicast &&
-                  tx->local->wpa_trigger & WPA_TRIGGER_FAIL_TX_MIC) {
-               printk(KERN_INFO "%s: WPA testing - corrupting TX Michael MIC "
-                      "for Group Key\n", tx->dev->name);
-               tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
-               tx->local->wpa_trigger &= ~WPA_TRIGGER_FAIL_TX_MIC;
-               tx->wpa_test = 1;
-               mic[0]++;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
        return TXRX_CONTINUE;
 }
 
@@ -169,34 +135,16 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 
        fc = rx->fc;
 
-       /* If device handles decryption totally, skip this check */
-       if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) ||
-           (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC))
+       /*
+        * No way to verify the MIC if the hardware stripped it
+        */
+       if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
                return TXRX_CONTINUE;
 
-       if (!rx->key || rx->key->alg != ALG_TKIP ||
+       if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
            !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
                return TXRX_CONTINUE;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (rx->sta && rx->sta->wpa_trigger & WPA_TRIGGER_FAIL_RX_MIC) {
-               wpa_test = 1;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-           !rx->key->force_sw_encrypt) {
-               if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
-                       if (skb->len < MICHAEL_MIC_LEN)
-                               return TXRX_DROP;
-               }
-               /* Need to verify Michael MIC sometimes in software even when
-                * hwaccel is used. Atheros ar5212: fragmented frames and QoS
-                * frames. */
-               if (!rx->fragmented && !wpa_test)
-                       goto remove_mic;
-       }
-
        if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
            || data_len < MICHAEL_MIC_LEN)
                return TXRX_DROP;
@@ -208,76 +156,28 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 #else
        authenticator = 1;
 #endif
-       key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
-                           ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
+       key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
+                                ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (rx->sta && rx->sta->wpa_trigger & WPA_TRIGGER_FAIL_RX_MIC) {
-               printk(KERN_INFO "%s: WPA testing - corrupting RX Michael MIC "
-                      "for STA " MAC_FMT "\n",
-                      rx->dev->name, MAC_ARG(rx->sta->addr));
-               rx->sta->wpa_trigger &= ~WPA_TRIGGER_FAIL_RX_MIC;
-               mic[0]++;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
        if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-               int i;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-               if (!rx->u.rx.ra_match)
+               if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
                        return TXRX_DROP;
 
                printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
                       MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-               printk(KERN_DEBUG "   received");
-               for (i = 0; i < MICHAEL_MIC_LEN; i++)
-                       printk(" %02x", data[data_len + i]);
-               printk(" expected");
-               for (i = 0; i < MICHAEL_MIC_LEN; i++)
-                       printk(" %02x", mic[i]);
-               printk("\n");
-               printk(KERN_DEBUG "   SA=" MAC_FMT " DA=" MAC_FMT " key",
-                      MAC_ARG(sa), MAC_ARG(da));
-               for (i = 0; i < 8; i++)
-                       printk(" %02x", key[i]);
-               printk(" (%d)\n", authenticator);
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-               do {
-                       struct ieee80211_hdr *hdr;
-                       union iwreq_data wrqu;
-                       char *buf = kmalloc(128, GFP_ATOMIC);
-                       if (!buf)
-                               break;
-
-                       /* TODO: needed parameters: count, key type, TSC */
-                       hdr = (struct ieee80211_hdr *) skb->data;
-                       sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-                               "keyid=%d %scast addr=" MAC_FMT ")",
-                               rx->key->keyidx,
-                               hdr->addr1[0] & 0x01 ? "broad" : "uni",
-                               MAC_ARG(hdr->addr2));
-                       memset(&wrqu, 0, sizeof(wrqu));
-                       wrqu.data.length = strlen(buf);
-                       wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
-                       kfree(buf);
-               } while (0);
-
-               if (!rx->local->apdev)
-                       return TXRX_DROP;
 
-               ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-                                 ieee80211_msg_michael_mic_failure);
-
-               return TXRX_QUEUED;
+               mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
+                                               (void *) skb->data);
+               return TXRX_DROP;
        }
 
- remove_mic:
        /* remove Michael MIC from payload */
        skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
 
+       /* update IV in key information to be able to detect replays */
+       rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32;
+       rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16;
+
        return TXRX_CONTINUE;
 }
 
@@ -295,7 +195,11 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
        hdrlen = ieee80211_get_hdrlen(fc);
        len = skb->len - hdrlen;
 
-       tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN;
+       if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+               tailneed = 0;
+       else
+               tailneed = TKIP_ICV_LEN;
+
        if ((skb_headroom(skb) < TKIP_IV_LEN ||
             skb_tailroom(skb) < tailneed)) {
                I802_DEBUG_INC(tx->local->tx_expand_skb_head);
@@ -308,31 +212,12 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
        memmove(pos, pos + TKIP_IV_LEN, hdrlen);
        pos += hdrlen;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (test & WPA_TRIGGER_TX_REPLAY)
-               goto skip_iv_inc;
-iv_inc:
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
        /* Increase IV for the frame */
        key->u.tkip.iv16++;
        if (key->u.tkip.iv16 == 0)
                key->u.tkip.iv32++;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (test & WPA_TRIGGER_TX_SKIP_SEQ) {
-               test = 0;
-               goto iv_inc;
-       }
-skip_iv_inc:
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       if (!tx->key->force_sw_encrypt
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-           && !tx->wpa_test
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-               ) {
-               u32 flags = tx->local->hw.flags;
+       if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                hdr = (struct ieee80211_hdr *)skb->data;
 
                /* hwaccel - with preallocated room for IV */
@@ -342,23 +227,7 @@ skip_iv_inc:
                                            0x7f),
                                      (u8) key->u.tkip.iv16);
 
-               if (flags & IEEE80211_HW_TKIP_REQ_PHASE2_KEY)
-                       ieee80211_tkip_gen_rc4key(key, hdr->addr2,
-                                                 tx->u.tx.control->tkip_key);
-               else if (flags & IEEE80211_HW_TKIP_REQ_PHASE1_KEY) {
-                       if (key->u.tkip.iv16 == 0 ||
-                           !key->u.tkip.tx_initialized) {
-                               ieee80211_tkip_gen_phase1key(key, hdr->addr2,
-                                           (u16 *)tx->u.tx.control->tkip_key);
-                               key->u.tkip.tx_initialized = 1;
-                               tx->u.tx.control->flags |=
-                                           IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
-                       } else
-                               tx->u.tx.control->flags &=
-                                           ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
-               }
-
-               tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+               tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
                return 0;
        }
 
@@ -373,59 +242,27 @@ skip_iv_inc:
 
 
 ieee80211_txrx_result
-ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
        u16 fc;
-       struct ieee80211_key *key = tx->key;
        struct sk_buff *skb = tx->skb;
        int wpa_test = 0, test = 0;
 
        fc = le16_to_cpu(hdr->frame_control);
 
-       if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc))
+       if (!WLAN_FC_DATA_PRESENT(fc))
                return TXRX_CONTINUE;
 
        tx->u.tx.control->icv_len = TKIP_ICV_LEN;
        tx->u.tx.control->iv_len = TKIP_IV_LEN;
        ieee80211_tx_set_iswep(tx);
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if ((tx->sta && tx->sta->wpa_trigger & WPA_TRIGGER_FAIL_TX_ICV) ||
-           (!tx->u.tx.unicast &&
-            tx->local->wpa_trigger & WPA_TRIGGER_FAIL_TX_ICV)) {
-               wpa_test = 1;
-       }
-
-       if (tx->sta) {
-               test = tx->sta->wpa_trigger;
-               tx->sta->wpa_trigger &=
-                       ~(WPA_TRIGGER_TX_REPLAY | WPA_TRIGGER_TX_REPLAY_FRAG |
-                         WPA_TRIGGER_TX_SKIP_SEQ);
-       } else {
-               test = tx->local->wpa_trigger;
-               tx->local->wpa_trigger &=
-                       ~(WPA_TRIGGER_TX_REPLAY | WPA_TRIGGER_TX_REPLAY_FRAG |
-                         WPA_TRIGGER_TX_SKIP_SEQ);
-       }
-       if (test &
-           (WPA_TRIGGER_TX_REPLAY | WPA_TRIGGER_TX_REPLAY_FRAG |
-            WPA_TRIGGER_TX_SKIP_SEQ)) {
-               printk(KERN_INFO "%s: WPA testing - TKIP TX packet number "
-                      "%s%s%s%s\n", tx->dev->name,
-                      tx->sta ? "[UNICAST]" : "[MULTICAST]",
-                      test & WPA_TRIGGER_TX_REPLAY ? "[REPLAY]" : "",
-                      test & WPA_TRIGGER_TX_REPLAY_FRAG ?
-                      "[REPLAY FRAG]" : "",
-                      test & WPA_TRIGGER_TX_SKIP_SEQ ? "[SKIP SEQ]" : "");
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       if (!tx->key->force_sw_encrypt &&
-           !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
            !wpa_test) {
                /* hwaccel - with no need for preallocated room for IV/ICV */
-               tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+               tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
                return TXRX_CONTINUE;
        }
 
@@ -434,10 +271,6 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx)
 
        if (tx->u.tx.extra_frag) {
                int i;
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-               if (test & WPA_TRIGGER_TX_REPLAY_FRAG)
-                       test |= WPA_TRIGGER_TX_REPLAY;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
                for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
                        if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
                            < 0)
@@ -445,31 +278,12 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx)
                }
        }
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (tx->sta && tx->sta->wpa_trigger & WPA_TRIGGER_FAIL_TX_ICV) {
-               printk(KERN_INFO "%s: WPA testing - corrupting TX TKIP ICV "
-                      "for STA " MAC_FMT "\n",
-                      tx->dev->name, MAC_ARG(tx->sta->addr));
-               tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
-               tx->sta->wpa_trigger &= ~WPA_TRIGGER_FAIL_TX_ICV;
-               skb->data[skb->len - 1]++;
-       } else if (!tx->u.tx.unicast &&
-                  tx->local->wpa_trigger & WPA_TRIGGER_FAIL_TX_ICV) {
-               printk(KERN_INFO "%s: WPA testing - corrupting TX TKIP ICV "
-                      "for Group Key\n",
-                      tx->dev->name);
-               tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
-               tx->local->wpa_trigger &= ~WPA_TRIGGER_FAIL_TX_ICV;
-               skb->data[skb->len - 1]++;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
        return TXRX_CONTINUE;
 }
 
 
 ieee80211_txrx_result
-ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
        u16 fc;
@@ -480,30 +294,19 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx)
        fc = le16_to_cpu(hdr->frame_control);
        hdrlen = ieee80211_get_hdrlen(fc);
 
-       if (!rx->key || rx->key->alg != ALG_TKIP ||
-           !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
-           (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+       if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
                return TXRX_CONTINUE;
 
        if (!rx->sta || skb->len - hdrlen < 12)
                return TXRX_DROP;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (rx->sta && rx->sta->wpa_trigger & WPA_TRIGGER_FAIL_RX_ICV) {
-               printk(KERN_INFO "%s: WPA testing - corrupting RX TKIP ICV "
-                      "for STA " MAC_FMT "\n",
-                      rx->dev->name, MAC_ARG(rx->sta->addr));
-               rx->sta->wpa_trigger &= ~WPA_TRIGGER_FAIL_RX_ICV;
-               skb->data[skb->len - 1]++;
-               wpa_test = 1;
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-           !rx->key->force_sw_encrypt) {
-               if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
-                       /* Hardware takes care of all processing, including
-                        * replay protection, so no need to continue here. */
+       if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
+               if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
+                       /*
+                        * Hardware took care of all processing, including
+                        * replay protection, and stripped the ICV/IV so
+                        * we cannot do any checks here.
+                        */
                        return TXRX_CONTINUE;
                }
 
@@ -514,7 +317,9 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx)
        res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
                                          key, skb->data + hdrlen,
                                          skb->len - hdrlen, rx->sta->addr,
-                                         hwaccel, rx->u.rx.queue);
+                                         hwaccel, rx->u.rx.queue,
+                                         &rx->u.rx.tkip_iv32,
+                                         &rx->u.rx.tkip_iv16);
        if (res != TKIP_DECRYPT_OK || wpa_test) {
                printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from "
                       MAC_FMT " (res=%d)\n",
@@ -644,7 +449,10 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
        hdrlen = ieee80211_get_hdrlen(fc);
        len = skb->len - hdrlen;
 
-       tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN;
+       if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+               tailneed = 0;
+       else
+               tailneed = CCMP_MIC_LEN;
 
        if ((skb_headroom(skb) < CCMP_HDR_LEN ||
             skb_tailroom(skb) < tailneed)) {
@@ -662,31 +470,17 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
        /* PN = PN + 1 */
        pn = key->u.ccmp.tx_pn;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (test & WPA_TRIGGER_TX_REPLAY)
-               goto skip_pn_inc;
-pn_inc:
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
        for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
                pn[i]++;
                if (pn[i])
                        break;
        }
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (test & WPA_TRIGGER_TX_SKIP_SEQ) {
-               test = 0;
-               goto pn_inc;
-       }
-skip_pn_inc:
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
-       ccmp_pn2hdr(pos, pn, key->keyidx);
+       ccmp_pn2hdr(pos, pn, key->conf.keyidx);
 
-       if (!key->force_sw_encrypt) {
+       if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                /* hwaccel - with preallocated room for CCMP header */
-               tx->u.tx.control->key_idx = key->hw_key_idx;
+               tx->u.tx.control->key_idx = key->conf.hw_key_idx;
                return 0;
        }
 
@@ -700,49 +494,27 @@ skip_pn_inc:
 
 
 ieee80211_txrx_result
-ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       struct ieee80211_key *key = tx->key;
        u16 fc;
        struct sk_buff *skb = tx->skb;
        int test = 0;
 
        fc = le16_to_cpu(hdr->frame_control);
 
-       if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc))
+       if (!WLAN_FC_DATA_PRESENT(fc))
                return TXRX_CONTINUE;
 
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-       if (tx->sta) {
-               test = tx->sta->wpa_trigger;
-               tx->sta->wpa_trigger = 0;
-       } else {
-               test = tx->local->wpa_trigger;
-               tx->local->wpa_trigger = 0;
-       }
-       if (test &
-           (WPA_TRIGGER_TX_REPLAY | WPA_TRIGGER_TX_REPLAY_FRAG |
-            WPA_TRIGGER_TX_SKIP_SEQ)) {
-               printk(KERN_INFO "%s: WPA testing - CCMP TX packet number "
-                      "%s%s%s%s\n", tx->dev->name,
-                      tx->sta ? "[UNICAST]" : "[MULTICAST]",
-                      test & WPA_TRIGGER_TX_REPLAY ? "[REPLAY]" : "",
-                      test & WPA_TRIGGER_TX_REPLAY_FRAG ?
-                      "[REPLAY FRAG]" : "",
-                      test & WPA_TRIGGER_TX_SKIP_SEQ ? "[SKIP SEQ]" : "");
-       }
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
-
        tx->u.tx.control->icv_len = CCMP_MIC_LEN;
        tx->u.tx.control->iv_len = CCMP_HDR_LEN;
        ieee80211_tx_set_iswep(tx);
 
-       if (!tx->key->force_sw_encrypt &&
-           !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
                /* hwaccel - with no need for preallocated room for CCMP "
                 * header or MIC fields */
-               tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+               tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
                return TXRX_CONTINUE;
        }
 
@@ -751,10 +523,6 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 
        if (tx->u.tx.extra_frag) {
                int i;
-#ifdef CONFIG_HOSTAPD_WPA_TESTING
-               if (test & WPA_TRIGGER_TX_REPLAY_FRAG)
-                       test |= WPA_TRIGGER_TX_REPLAY;
-#endif /* CONFIG_HOSTAPD_WPA_TESTING */
                for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
                        if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
                            < 0)
@@ -767,7 +535,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 
 
 ieee80211_txrx_result
-ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
        u16 fc;
@@ -780,9 +548,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
        fc = le16_to_cpu(hdr->frame_control);
        hdrlen = ieee80211_get_hdrlen(fc);
 
-       if (!key || key->alg != ALG_CCMP ||
-           !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
-           (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+       if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
                return TXRX_CONTINUE;
 
        data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
@@ -790,8 +556,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
                return TXRX_DROP;
 
        if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-           !key->force_sw_encrypt &&
-           !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
+           (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
                return TXRX_CONTINUE;
 
        (void) ccmp_hdr2pn(pn, skb->data + hdrlen);
@@ -810,10 +575,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
                return TXRX_DROP;
        }
 
-       if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-           !key->force_sw_encrypt) {
-               /* hwaccel has already decrypted frame and verified MIC */
-       } else {
+       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+               /* hardware didn't decrypt/verify MIC */
                u8 *scratch, *b_0, *aad;
 
                scratch = key->u.ccmp.rx_crypto_buf;
index da3b9594f9c3e9cc7f187dc515c27cd37b89a270..49d80cf0cd7569fb5f409121f017b185f0e76bdf 100644 (file)
@@ -19,13 +19,13 @@ ieee80211_txrx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
 
 ieee80211_txrx_result
-ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx);
 ieee80211_txrx_result
-ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx);
 
 ieee80211_txrx_result
-ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx);
 ieee80211_txrx_result
-ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx);
 
 #endif /* WPA_H */
index e746b3af8c3e9314f36d7a3299927c88f8e280ed..5664c2cfd7600323d74a85d36b5ba5dcf225c270 100644 (file)
@@ -1,5 +1,4 @@
-obj-$(CONFIG_WIRELESS_EXT) += wext.o
 obj-$(CONFIG_CFG80211) += cfg80211.o
 
-cfg80211-y += core.o sysfs.o
+cfg80211-y += core.o sysfs.o radiotap.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
index 46e5ae07044fdf811602253347f3c8ca48ba1e43..35b79bee3a628ac890db77694db85dc6d9121e17 100644 (file)
@@ -162,10 +162,15 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 
        /* this will check for collisions */
        result = device_rename(&rdev->wiphy.dev, newname);
-       if (!result)
+       if (result)
                return result;
 
-       /* TODO: do debugfs rename! */
+       if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
+                           rdev->wiphy.debugfsdir,
+                           rdev->wiphy.debugfsdir->d_parent,
+                           newname))
+               printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
+                      newname);
 
        nl80211_notify_dev_rename(rdev);
 
@@ -355,7 +360,7 @@ out_fail_notifier:
 out_fail_sysfs:
        return err;
 }
-module_init(cfg80211_init);
+subsys_initcall(cfg80211_init);
 
 static void cfg80211_exit(void)
 {
index ffbe6288a28ac1aa0ae65c1e6d0055286f0d161c..58717f303763c7d9811a1dad762716bee8f0367f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This is the new netlink-based wireless configuration interface.
  *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007        Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/if.h>
@@ -13,6 +13,7 @@
 #include <linux/ieee80211.h>
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
+#include <linux/netlink.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
 #include "core.h"
@@ -27,22 +28,6 @@ static struct genl_family nl80211_fam = {
        .maxattr = NL80211_ATTR_MAX,
 };
 
-/* internal helper: validate an information element attribute */
-static int check_information_element(struct nlattr *nla)
-{
-       int len = nla_len(nla);
-       u8 *data = nla_data(nla);
-       int elementlen;
-
-       while (len >= 2) {
-               /* 1 byte ID, 1 byte len, `len' bytes data */
-               elementlen = *(data+1) + 2;
-               data += elementlen;
-               len -= elementlen;
-       }
-       return len ? -EINVAL : 0;
-}
-
 /* internal helper: get drv and dev */
 static int get_drv_dev_by_info_ifindex(struct genl_info *info,
                                       struct cfg80211_registered_device **drv,
@@ -55,7 +40,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
 
        ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
        *dev = dev_get_by_index(ifindex);
-       if (!dev)
+       if (!*dev)
                return -ENODEV;
 
        *drv = cfg80211_get_dev_from_ifindex(ifindex);
@@ -69,287 +54,194 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
 
 /* policy for the attributes */
 static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
-       [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
-       [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
                                      .len = BUS_ID_SIZE-1 },
+
        [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
-       [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
-       [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
-                               .len = IEEE80211_MAX_SSID_LEN },
-       [NL80211_ATTR_CHANNEL] = { .type = NLA_U32 },
-       [NL80211_ATTR_PHYMODE] = { .type = NLA_U32 },
-       [NL80211_ATTR_CHANNEL_LIST] = { .type = NLA_NESTED },
-       [NL80211_ATTR_BSS_LIST] = { .type = NLA_NESTED },
-       [NL80211_ATTR_BSSTYPE] = { .type = NLA_U32 },
-       [NL80211_ATTR_BEACON_PERIOD] = { .type = NLA_U32 },
-       [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
-       [NL80211_ATTR_TIMESTAMP] = { .type = NLA_U64 },
-       [NL80211_ATTR_IE] = { .type = NLA_BINARY, .len = NL80211_MAX_IE_LEN },
-       [NL80211_ATTR_AUTH_ALGORITHM] = { .type = NLA_U32 },
-       [NL80211_ATTR_TIMEOUT_TU] = { .type = NLA_U32 },
-       [NL80211_ATTR_REASON_CODE] = { .type = NLA_U32 },
-       [NL80211_ATTR_ASSOCIATION_ID] = { .type = NLA_U16 },
-       [NL80211_ATTR_DEAUTHENTICATED] = { .type = NLA_FLAG },
-       [NL80211_ATTR_RX_SENSITIVITY] = { .type = NLA_U32 },
-       [NL80211_ATTR_TRANSMIT_POWER] = { .type = NLA_U32 },
-       [NL80211_ATTR_FRAG_THRESHOLD] = { .type = NLA_U32 },
-       [NL80211_ATTR_FLAG_SCAN_ACTIVE] = { .type = NLA_FLAG },
-       [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY },
-       [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY },
-       [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
-                                   .len = WLAN_MAX_KEY_LEN },
-       [NL80211_ATTR_KEY_ID] = { .type = NLA_U32 },
-       [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
-       [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
-       [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+       [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
+       [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
 };
 
-/* netlink command implementations */
+/* message building helper */
+static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
+                                  int flags, u8 cmd)
+{
+       /* since there is no private header just add the generic one */
+       return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
+}
 
-#define CHECK_CMD(ptr, cmd)                            \
-       if (drv->ops->ptr)                              \
-               NLA_PUT_FLAG(msg, NL80211_CMD_##cmd);
+/* netlink command implementations */
 
-static int nl80211_get_cmdlist(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+                             struct cfg80211_registered_device *dev)
 {
-       struct cfg80211_registered_device *drv;
-       struct sk_buff *msg;
        void *hdr;
-       int err;
-       struct nlattr *start;
 
-       drv = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(drv))
-               return PTR_ERR(drv);
-
-       hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_NEW_CMDLIST);
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto put_drv;
-       }
+       hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
+       if (!hdr)
+               return -1;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
+       NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+       return genlmsg_end(msg, hdr);
 
-       start = nla_nest_start(msg, NL80211_ATTR_CMDS);
-       if (!start)
-               goto nla_put_failure;
-
-       /* unconditionally allow some common commands we handle centrally
-        * or where we require the implementation */
-       NLA_PUT_FLAG(msg, NL80211_CMD_GET_CMDLIST);
-       NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS);
-       NLA_PUT_FLAG(msg, NL80211_CMD_GET_INTERFACES);
-       NLA_PUT_FLAG(msg, NL80211_CMD_RENAME_WIPHY);
-
-       CHECK_CMD(add_virtual_intf, ADD_VIRTUAL_INTERFACE);
-       CHECK_CMD(del_virtual_intf, DEL_VIRTUAL_INTERFACE);
-       CHECK_CMD(associate, ASSOCIATE);
-       CHECK_CMD(disassociate, DISASSOCIATE);
-       CHECK_CMD(deauth, DEAUTH);
-       CHECK_CMD(initiate_scan, INITIATE_SCAN);
-       CHECK_CMD(get_association, GET_ASSOCIATION);
-       CHECK_CMD(get_auth_list, GET_AUTH_LIST);
-       CHECK_CMD(add_key, ADD_KEY);
-       CHECK_CMD(del_key, DEL_KEY);
+ nla_put_failure:
+       return genlmsg_cancel(msg, hdr);
+}
 
-       nla_nest_end(msg, start);
+static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       int idx = 0;
+       int start = cb->args[0];
+       struct cfg80211_registered_device *dev;
 
-       genlmsg_end(msg, hdr);
+       mutex_lock(&cfg80211_drv_mutex);
+       list_for_each_entry(dev, &cfg80211_drv_list, list) {
+               if (++idx < start)
+                       continue;
+               if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
+                                      cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                      dev) < 0)
+                       break;
+       }
+       mutex_unlock(&cfg80211_drv_mutex);
 
-       err = genlmsg_unicast(msg, info->snd_pid);
-       goto put_drv;
+       cb->args[0] = idx;
 
- nla_put_failure:
-       err = -ENOBUFS;
-       nlmsg_free(msg);
- put_drv:
-       cfg80211_put_dev(drv);
-       return err;
+       return skb->len;
 }
-#undef CHECK_CMD
 
-static int nl80211_get_wiphys(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       void *hdr;
-       struct nlattr *start, *indexstart;
-       struct cfg80211_registered_device *drv;
-       int idx = 1;
-
-       hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_NEW_WIPHYS);
-       if (IS_ERR(hdr))
-               return PTR_ERR(hdr);
+       struct cfg80211_registered_device *dev;
 
-       start = nla_nest_start(msg, NL80211_ATTR_WIPHY_LIST);
-       if (!start)
-               goto nla_outer_nest_failure;
+       dev = cfg80211_get_dev_from_info(info);
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
 
-       mutex_lock(&cfg80211_drv_mutex);
-       list_for_each_entry(drv, &cfg80211_drv_list, list) {
-               indexstart = nla_nest_start(msg, idx++);
-               if (!indexstart)
-                       goto nla_put_failure;
-               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
-               nla_nest_end(msg, indexstart);
-       }
-       mutex_unlock(&cfg80211_drv_mutex);
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               goto out_err;
 
-       nla_nest_end(msg, start);
+       if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
+               goto out_free;
 
-       genlmsg_end(msg, hdr);
+       cfg80211_put_dev(dev);
 
        return genlmsg_unicast(msg, info->snd_pid);
 
- nla_put_failure:
-       mutex_unlock(&cfg80211_drv_mutex);
- nla_outer_nest_failure:
+ out_free:
        nlmsg_free(msg);
+ out_err:
+       cfg80211_put_dev(dev);
        return -ENOBUFS;
 }
 
-static int addifidx(struct net_device *dev, struct sk_buff *skb, int *idx)
+static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
-       int err = -ENOBUFS;
-       struct nlattr *start;
-
-       dev_hold(dev);
+       struct cfg80211_registered_device *rdev;
+       int result;
 
-       start = nla_nest_start(skb, *idx++);
-       if (!start)
-               goto nla_put_failure;
+       if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
+               return -EINVAL;
 
-       NLA_PUT_U32(skb, NL80211_ATTR_IFINDEX, dev->ifindex);
-       NLA_PUT_STRING(skb, NL80211_ATTR_IFNAME, dev->name);
+       rdev = cfg80211_get_dev_from_info(info);
+       if (IS_ERR(rdev))
+               return PTR_ERR(rdev);
 
-       nla_nest_end(skb, start);
-       err = 0;
+       result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
 
- nla_put_failure:
-       dev_put(dev);
-       return err;
+       cfg80211_put_dev(rdev);
+       return result;
 }
 
-static int nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)
+
+static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+                             struct net_device *dev)
 {
-       struct cfg80211_registered_device *drv;
-       struct sk_buff *msg;
        void *hdr;
-       int err, array_idx;
-       struct nlattr *start;
-       struct wireless_dev *wdev;
-
-       drv = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(drv))
-               return PTR_ERR(drv);
-
-       hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_NEW_INTERFACES);
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto put_drv;
-       }
 
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
+       hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
+       if (!hdr)
+               return -1;
 
-       start = nla_nest_start(msg, NL80211_ATTR_INTERFACE_LIST);
-       if (!start) {
-               err = -ENOBUFS;
-               goto msg_free;
-       }
-
-       array_idx = 1;
-       err = 0;
-       mutex_lock(&drv->devlist_mtx);
-       list_for_each_entry(wdev, &drv->netdev_list, list) {
-               err = addifidx(wdev->netdev, msg, &array_idx);
-               if (err)
-                       break;
-       }
-       mutex_unlock(&drv->devlist_mtx);
-       if (err)
-               goto msg_free;
-
-       nla_nest_end(msg, start);
-
-       genlmsg_end(msg, hdr);
-
-       err = genlmsg_unicast(msg, info->snd_pid);
-       goto put_drv;
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
+       /* TODO: interface type */
+       return genlmsg_end(msg, hdr);
 
  nla_put_failure:
-       err = -ENOBUFS;
- msg_free:
-       nlmsg_free(msg);
- put_drv:
-       cfg80211_put_dev(drv);
-       return err;
+       return genlmsg_cancel(msg, hdr);
 }
 
-static int nl80211_add_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct cfg80211_registered_device *drv;
-       int err;
-       enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
-
-       if (!info->attrs[NL80211_ATTR_IFNAME])
-               return -EINVAL;
+       int wp_idx = 0;
+       int if_idx = 0;
+       int wp_start = cb->args[0];
+       int if_start = cb->args[1];
+       struct cfg80211_registered_device *dev;
+       struct wireless_dev *wdev;
 
-       if (info->attrs[NL80211_ATTR_IFTYPE]) {
-               type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
-               if (type > NL80211_IFTYPE_MAX)
-                       return -EINVAL;
+       mutex_lock(&cfg80211_drv_mutex);
+       list_for_each_entry(dev, &cfg80211_drv_list, list) {
+               if (++wp_idx < wp_start)
+                       continue;
+               if_idx = 0;
+
+               mutex_lock(&dev->devlist_mtx);
+               list_for_each_entry(wdev, &dev->netdev_list, list) {
+                       if (++if_idx < if_start)
+                               continue;
+                       if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
+                                              cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                              wdev->netdev) < 0)
+                               break;
+               }
+               mutex_unlock(&dev->devlist_mtx);
        }
+       mutex_unlock(&cfg80211_drv_mutex);
 
-       drv = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(drv))
-               return PTR_ERR(drv);
-
-       if (!drv->ops->add_virtual_intf) {
-               err = -EOPNOTSUPP;
-               goto unlock;
-       }
+       cb->args[0] = wp_idx;
+       cb->args[1] = if_idx;
 
-       rtnl_lock();
-       err = drv->ops->add_virtual_intf(&drv->wiphy,
-               nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
-       rtnl_unlock();
-
- unlock:
-       cfg80211_put_dev(drv);
-       return err;
+       return skb->len;
 }
 
-static int nl80211_del_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
-       int ifindex, err;
-       struct net_device *dev;
+       struct sk_buff *msg;
+       struct cfg80211_registered_device *dev;
+       struct net_device *netdev;
+       int err;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
        if (err)
                return err;
-       ifindex = dev->ifindex;
-       dev_put(dev);
 
-       if (!drv->ops->del_virtual_intf) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               goto out_err;
 
-       rtnl_lock();
-       err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
-       rtnl_unlock();
+       if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
+               goto out_free;
 
- out:
-       cfg80211_put_dev(drv);
-       return err;
+       dev_put(netdev);
+       cfg80211_put_dev(dev);
+
+       return genlmsg_unicast(msg, info->snd_pid);
+
+ out_free:
+       nlmsg_free(msg);
+ out_err:
+       dev_put(netdev);
+       cfg80211_put_dev(dev);
+       return -ENOBUFS;
 }
 
-static int nl80211_change_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
        int err, ifindex;
@@ -383,588 +275,128 @@ static int nl80211_change_virt_intf(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
-static int nl80211_get_association(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
        int err;
-       struct net_device *dev;
-       struct sk_buff *msg;
-       void *hdr;
-       u8 bssid[ETH_ALEN];
-
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-       if (err)
-               return err;
-
-       if (!drv->ops->get_association) {
-               err = -EOPNOTSUPP;
-               goto out_put_drv;
-       }
-
-       rtnl_lock();
-       err = drv->ops->get_association(&drv->wiphy, dev, bssid);
-       rtnl_unlock();
-       if (err < 0)
-               goto out_put_drv;
-
-       hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_ASSOCIATION_CHANGED);
-
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto out_put_drv;
-       }
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-       if (err == 1)
-               NLA_PUT(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
-
-       genlmsg_end(msg, hdr);
-       err = genlmsg_unicast(msg, info->snd_pid);
-       goto out_put_drv;
-
- nla_put_failure:
-       err = -ENOBUFS;
-       nlmsg_free(msg);
- out_put_drv:
-       cfg80211_put_dev(drv);
-       dev_put(dev);
-       return err;
-}
-
-static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
-{
-       struct cfg80211_registered_device *drv;
-       int err;
-       struct net_device *dev;
-       struct association_params assoc_params;
-
-       memset(&assoc_params, 0, sizeof(assoc_params));
-
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-       if (err)
-               return err;
-
-       if (!drv->ops->associate) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
 
-       if (!info->attrs[NL80211_ATTR_SSID])
+       if (!info->attrs[NL80211_ATTR_IFNAME])
                return -EINVAL;
 
-       assoc_params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
-       assoc_params.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
-
-       if (info->attrs[NL80211_ATTR_BSSID])
-               assoc_params.bssid = nla_data(info->attrs[NL80211_ATTR_BSSID]);
-
-       if (info->attrs[NL80211_ATTR_IE]) {
-               err = check_information_element(info->attrs[NL80211_ATTR_IE]);
-               if (err)
-                       goto out;
-               assoc_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               assoc_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
-       }
-
-       if (info->attrs[NL80211_ATTR_TIMEOUT_TU]) {
-               assoc_params.timeout =
-                       nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT_TU]);
-               assoc_params.valid |= ASSOC_PARAMS_TIMEOUT;
-       }
-
-       rtnl_lock();
-       err = drv->ops->associate(&drv->wiphy, dev, &assoc_params);
-       rtnl_unlock();
-
- out:
-       cfg80211_put_dev(drv);
-       dev_put(dev);
-       return err;
-}
-
-static int nl80211_disassoc_deauth(struct sk_buff *skb, struct genl_info *info)
-{
-       struct cfg80211_registered_device *drv;
-       int err;
-       struct net_device *dev;
-       int (*act)(struct wiphy *wiphy, struct net_device *dev);
-
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-       if (err)
-               return err;
-
-       switch (info->genlhdr->cmd) {
-       case NL80211_CMD_DISASSOCIATE:
-               act = drv->ops->disassociate;
-               break;
-       case NL80211_CMD_DEAUTH:
-               act = drv->ops->deauth;
-               break;
-       default:
-               act = NULL;
-       }
-
-       if (!act) {
-               err = -EOPNOTSUPP;
-               goto out;
+       if (info->attrs[NL80211_ATTR_IFTYPE]) {
+               type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+               if (type > NL80211_IFTYPE_MAX)
+                       return -EINVAL;
        }
 
-       rtnl_lock();
-       err = act(&drv->wiphy, dev);
-       rtnl_unlock();
- out:
-       cfg80211_put_dev(drv);
-       dev_put(dev);
-       return err;
-}
-
-struct add_cb_data {
-       int idx;
-       struct sk_buff *skb;
-};
-
-static int add_bssid(void *data, u8 *bssid)
-{
-       struct add_cb_data *cb = data;
-       int err = -ENOBUFS;
-       struct nlattr *start;
-
-       start = nla_nest_start(cb->skb, cb->idx++);
-       if (!start)
-               goto nla_put_failure;
-
-       NLA_PUT(cb->skb, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
-
-       nla_nest_end(cb->skb, start);
-       err = 0;
-
- nla_put_failure:
-       return err;
-}
-
-static int nl80211_get_auth_list(struct sk_buff *skb, struct genl_info *info)
-{
-       struct cfg80211_registered_device *drv;
-       struct net_device *dev;
-       struct sk_buff *msg;
-       void *hdr;
-       int err;
-       struct nlattr *start;
-       struct add_cb_data cb;
-
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-       if (err)
-               return err;
+       drv = cfg80211_get_dev_from_info(info);
+       if (IS_ERR(drv))
+               return PTR_ERR(drv);
 
-       if (!drv->ops->get_auth_list) {
+       if (!drv->ops->add_virtual_intf) {
                err = -EOPNOTSUPP;
-               goto put_drv;
-       }
-
-       hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_NEW_AUTH_LIST);
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto put_drv;
-       }
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-
-       start = nla_nest_start(msg, NL80211_ATTR_BSS_LIST);
-       if (!start) {
-               err = -ENOBUFS;
-               goto msg_free;
+               goto unlock;
        }
 
-       cb.skb = msg;
-       cb.idx = 1;
        rtnl_lock();
-       err = drv->ops->get_auth_list(&drv->wiphy, dev, &cb, add_bssid);
+       err = drv->ops->add_virtual_intf(&drv->wiphy,
+               nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
        rtnl_unlock();
-       if (err)
-               goto msg_free;
-
-       nla_nest_end(msg, start);
 
-       genlmsg_end(msg, hdr);
-
-       err = genlmsg_unicast(msg, info->snd_pid);
-       goto put_drv;
-
- nla_put_failure:
-       err = -ENOBUFS;
- msg_free:
-       nlmsg_free(msg);
- put_drv:
+ unlock:
        cfg80211_put_dev(drv);
-       dev_put(dev);
        return err;
 }
 
-static int nl80211_initiate_scan(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
-       int err;
+       int ifindex, err;
        struct net_device *dev;
-       struct scan_params params;
-       struct scan_channel *channels = NULL;
-       int count = -1;
-
-       if (info->attrs[NL80211_ATTR_PHYMODE])
-               params.phymode = nla_get_u32(info->attrs[NL80211_ATTR_PHYMODE]);
-
-       if (params.phymode > NL80211_PHYMODE_MAX)
-               return -EINVAL;
 
        err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
        if (err)
                return err;
-
-       if (!drv->ops->initiate_scan) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       params.active = nla_get_flag(info->attrs[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
-
-       if (info->attrs[NL80211_ATTR_CHANNEL_LIST]) {
-               struct nlattr *attr = info->attrs[NL80211_ATTR_CHANNEL_LIST];
-               struct nlattr *nla;
-               int rem;
-               struct nlattr **tb;
-
-               /* let's count first */
-               count = 0;
-               nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem)
-                       count++;
-
-               if (count == 0) {
-                       /* assume we should actually scan all channels,
-                        * scanning no channels make no sense */
-                       count = -1;
-                       goto done_channels;
-               }
-
-               if (count > NL80211_MAX_CHANNEL_LIST_ITEM) {
-                       err = -EINVAL;
-                       goto out;
-               }
-
-               channels = kmalloc(count * sizeof(struct scan_channel),
-                                  GFP_KERNEL);
-               tb = kmalloc((NL80211_ATTR_MAX+1) * sizeof(struct nlattr),
-                            GFP_KERNEL);
-
-               count = 0;
-               nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem) {
-                       err = nla_parse(tb, NL80211_ATTR_MAX, nla_data(nla),
-                                       nla_len(nla), nl80211_policy);
-
-                       if (err || !tb[NL80211_ATTR_CHANNEL]) {
-                               err = -EINVAL;
-                               kfree(tb);
-                               kfree(channels);
-                               goto out;
-                       }
-
-                       channels[count].phymode = params.phymode;
-
-                       if (tb[NL80211_ATTR_PHYMODE])
-                               channels[count].phymode =
-                                       nla_get_u32(tb[NL80211_ATTR_PHYMODE]);
-
-                       if (channels[count].phymode > NL80211_PHYMODE_MAX) {
-                               err = -EINVAL;
-                               kfree(tb);
-                               kfree(channels);
-                               goto out;
-                       }
-
-                       channels[count].channel =
-                               nla_get_u32(tb[NL80211_ATTR_CHANNEL]);
-
-                       channels[count].active =
-                               nla_get_flag(tb[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
-                       count++;
-               }
-               kfree(tb);
-       }
-
- done_channels:
-       params.channels = channels;
-       params.n_channels = count;
-
-       rtnl_lock();
-       err = drv->ops->initiate_scan(&drv->wiphy, dev, &params);
-       rtnl_unlock();
-
-       kfree(channels);
- out:
-       cfg80211_put_dev(drv);
+       ifindex = dev->ifindex;
        dev_put(dev);
-       return err;
-}
-
-static int nl80211_rename_wiphy(struct sk_buff *skb, struct genl_info *info)
-{
-       struct cfg80211_registered_device *rdev;
-       int result;
-
-       if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
-               return -EINVAL;
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev))
-               return PTR_ERR(rdev);
-
-       result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
-
-       cfg80211_put_dev(rdev);
-       return result;
-}
 
-static int nl80211_key_cmd(struct sk_buff *skb, struct genl_info *info)
-{
-       struct cfg80211_registered_device *drv;
-       int err, del;
-       struct net_device *dev;
-       struct key_params params;
-       int (*act)(struct wiphy *wiphy, struct net_device *dev,
-                  struct key_params *params);
-
-       memset(&params, 0, sizeof(params));
-
-       if (!info->attrs[NL80211_ATTR_KEY_TYPE])
-               return -EINVAL;
-
-       if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
-               return -EINVAL;
-
-       params.key_type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
-       if (params.key_type > NL80211_KEYTYPE_MAX)
-               return -EINVAL;
-
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-       if (err)
-               return err;
-
-       switch (info->genlhdr->cmd) {
-       case NL80211_CMD_ADD_KEY:
-               act = drv->ops->add_key;
-               del = 0;
-               break;
-       case NL80211_CMD_DEL_KEY:
-               act = drv->ops->del_key;
-               del = 1;
-               break;
-       default:
-               act = NULL;
-       }
-
-       if (!act) {
+       if (!drv->ops->del_virtual_intf) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       if (info->attrs[NL80211_ATTR_KEY_DATA]) {
-               params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
-               params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
-       }
-
-       if (info->attrs[NL80211_ATTR_KEY_ID]) {
-               params.key_id = nla_get_u32(info->attrs[NL80211_ATTR_KEY_ID]);
-       } else {
-               params.key_id = -1;
-       }
-
-       params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
-       if (info->attrs[NL80211_ATTR_MAC]) {
-               params.macaddress = nla_data(info->attrs[NL80211_ATTR_MAC]);
-       } else {
-               params.macaddress = NULL;
-       }
-
        rtnl_lock();
-       err = act(&drv->wiphy, dev, &params);
+       err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
        rtnl_unlock();
 
  out:
        cfg80211_put_dev(drv);
-       dev_put(dev);
        return err;
 }
 
 static struct genl_ops nl80211_ops[] = {
        {
-               .cmd = NL80211_CMD_RENAME_WIPHY,
-               .doit = nl80211_rename_wiphy,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_GET_CMDLIST,
-               .doit = nl80211_get_cmdlist,
-               .policy = nl80211_policy,
-               /* can be retrieved by unprivileged users */
-       },
-       {
-               .cmd = NL80211_CMD_ADD_VIRTUAL_INTERFACE,
-               .doit = nl80211_add_virt_intf,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_DEL_VIRTUAL_INTERFACE,
-               .doit = nl80211_del_virt_intf,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_CHANGE_VIRTUAL_INTERFACE,
-               .doit = nl80211_change_virt_intf,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_GET_WIPHYS,
-               .doit = nl80211_get_wiphys,
+               .cmd = NL80211_CMD_GET_WIPHY,
+               .doit = nl80211_get_wiphy,
+               .dumpit = nl80211_dump_wiphy,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
        },
        {
-               .cmd = NL80211_CMD_GET_INTERFACES,
-               .doit = nl80211_get_intfs,
-               .policy = nl80211_policy,
-               /* can be retrieved by unprivileged users */
-       },
-       {
-               .cmd = NL80211_CMD_INITIATE_SCAN,
-               .doit = nl80211_initiate_scan,
+               .cmd = NL80211_CMD_SET_WIPHY,
+               .doit = nl80211_set_wiphy,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = NL80211_CMD_GET_ASSOCIATION,
-               .doit = nl80211_get_association,
+               .cmd = NL80211_CMD_GET_INTERFACE,
+               .doit = nl80211_get_interface,
+               .dumpit = nl80211_dump_interface,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
        },
        {
-               .cmd = NL80211_CMD_ASSOCIATE,
-               .doit = nl80211_associate,
+               .cmd = NL80211_CMD_SET_INTERFACE,
+               .doit = nl80211_set_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = NL80211_CMD_DISASSOCIATE,
-               .doit = nl80211_disassoc_deauth,
+               .cmd = NL80211_CMD_NEW_INTERFACE,
+               .doit = nl80211_new_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = NL80211_CMD_DEAUTH,
-               .doit = nl80211_disassoc_deauth,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_GET_AUTH_LIST,
-               .doit = nl80211_get_auth_list,
-               .policy = nl80211_policy,
-               /* can be retrieved by unprivileged users */
-       },
-/*
-       {
-               .cmd = NL80211_CMD_AP_SET_BEACON,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_AP_ADD_STA,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_AP_UPDATE_STA,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_AP_GET_STA_INFO,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_AP_SET_RATESETS,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-*/
-       {
-               .cmd = NL80211_CMD_ADD_KEY,
-               .doit = nl80211_key_cmd,
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = NL80211_CMD_DEL_KEY,
-               .doit = nl80211_key_cmd,
+               .cmd = NL80211_CMD_DEL_INTERFACE,
+               .doit = nl80211_del_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
 };
 
-
-/* exported functions */
-
-void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd)
-{
-       /* since there is no private header just add the generic one */
-       return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
-}
-EXPORT_SYMBOL_GPL(nl80211hdr_put);
-
-void *nl80211msg_new(struct sk_buff **skb, u32 pid, u32 seq, int flags, u8 cmd)
-{
-       void *hdr;
-
-       *skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!*skb)
-               return ERR_PTR(-ENOBUFS);
-
-       hdr = nl80211hdr_put(*skb, pid, seq, flags, cmd);
-       if (!hdr) {
-               nlmsg_free(*skb);
-               return ERR_PTR(-ENOBUFS);
-       }
-
-       return hdr;
-}
-EXPORT_SYMBOL_GPL(nl80211msg_new);
+/* multicast groups */
+static struct genl_multicast_group nl80211_config_mcgrp = {
+       .name = "config",
+};
 
 /* notification functions */
 
 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
 {
        struct sk_buff *msg;
-       void *hdr;
 
-       hdr = nl80211msg_new(&msg, 0, 0, 0, NL80211_CMD_WIPHY_NEWNAME);
-       if (IS_ERR(hdr))
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
                return;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
-       NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&rdev->wiphy));
-
-       genlmsg_end(msg, hdr);
-       genlmsg_multicast(msg, 0, NL80211_GROUP_CONFIG, GFP_KERNEL);
-
-       return;
+       if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
 
- nla_put_failure:
-       nlmsg_free(msg);
+       genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
 }
 
 /* initialisation/exit functions */
@@ -982,6 +414,11 @@ int nl80211_init(void)
                if (err)
                        goto err_out;
        }
+
+       err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
+       if (err)
+               goto err_out;
+
        return 0;
  err_out:
        genl_unregister_family(&nl80211_fam);
diff --git a/package/mac80211/src/wireless/radiotap.c b/package/mac80211/src/wireless/radiotap.c
new file mode 100644 (file)
index 0000000..28fbd0b
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007              Andy Green <andy@warmcat.com>
+ */
+
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
+
+/* function prototypes and related defs are in include/net/cfg80211.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header.  It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code.  Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member.  This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned.  Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+    struct ieee80211_radiotap_iterator *iterator,
+    struct ieee80211_radiotap_header *radiotap_header,
+    int max_length)
+{
+       /* Linux only supports version 0 radiotap format */
+       if (radiotap_header->it_version)
+               return -EINVAL;
+
+       /* sanity check for allowed length and radiotap length field */
+       if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+               return -EINVAL;
+
+       iterator->rtheader = radiotap_header;
+       iterator->max_length = le16_to_cpu(get_unaligned(
+                                               &radiotap_header->it_len));
+       iterator->arg_index = 0;
+       iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+                                               &radiotap_header->it_present));
+       iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+       iterator->this_arg = NULL;
+
+       /* find payload start allowing for extended bitmap(s) */
+
+       if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+               while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+                                  (1<<IEEE80211_RADIOTAP_EXT)) {
+                       iterator->arg += sizeof(u32);
+
+                       /*
+                        * check for insanity where the present bitmaps
+                        * keep claiming to extend up to or even beyond the
+                        * stated radiotap header length
+                        */
+
+                       if (((ulong)iterator->arg -
+                            (ulong)iterator->rtheader) > iterator->max_length)
+                               return -EINVAL;
+               }
+
+               iterator->arg += sizeof(u32);
+
+               /*
+                * no need to check again for blowing past stated radiotap
+                * header length, because ieee80211_radiotap_iterator_next
+                * checks it before it is dereferenced
+                */
+       }
+
+       /* we are all initialized happily */
+
+       return 0;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field.  It takes care of alignment handling and extended
+ * present fields.  @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL).  The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned.  Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+    struct ieee80211_radiotap_iterator *iterator)
+{
+
+       /*
+        * small length lookup table for all radiotap types we heard of
+        * starting from b0 in the bitmap, so we can walk the payload
+        * area of the radiotap header
+        *
+        * There is a requirement to pad args, so that args
+        * of a given length must begin at a boundary of that length
+        * -- but note that compound args are allowed (eg, 2 x u16
+        * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+        * a reliable indicator of alignment requirement.
+        *
+        * upper nybble: content alignment for arg
+        * lower nybble: content length for arg
+        */
+
+       static const u8 rt_sizes[] = {
+               [IEEE80211_RADIOTAP_TSFT] = 0x88,
+               [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+               [IEEE80211_RADIOTAP_RATE] = 0x11,
+               [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+               [IEEE80211_RADIOTAP_FHSS] = 0x22,
+               [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+               [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+               [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+               [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+               [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+               [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+               [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+               [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+               [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+               [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+               [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+               [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+               [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
+               /*
+                * add more here as they are defined in
+                * include/net/ieee80211_radiotap.h
+                */
+       };
+
+       /*
+        * for every radiotap entry we can at
+        * least skip (by knowing the length)...
+        */
+
+       while (iterator->arg_index < sizeof(rt_sizes)) {
+               int hit = 0;
+               int pad;
+
+               if (!(iterator->bitmap_shifter & 1))
+                       goto next_entry; /* arg not present */
+
+               /*
+                * arg is present, account for alignment padding
+                *  8-bit args can be at any alignment
+                * 16-bit args must start on 16-bit boundary
+                * 32-bit args must start on 32-bit boundary
+                * 64-bit args must start on 64-bit boundary
+                *
+                * note that total arg size can differ from alignment of
+                * elements inside arg, so we use upper nybble of length
+                * table to base alignment on
+                *
+                * also note: these alignments are ** relative to the
+                * start of the radiotap header **.  There is no guarantee
+                * that the radiotap header itself is aligned on any
+                * kind of boundary.
+                *
+                * the above is why get_unaligned() is used to dereference
+                * multibyte elements from the radiotap area
+                */
+
+               pad = (((ulong)iterator->arg) -
+                       ((ulong)iterator->rtheader)) &
+                       ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+               if (pad)
+                       iterator->arg +=
+                               (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+               /*
+                * this is what we will return to user, but we need to
+                * move on first so next call has something fresh to test
+                */
+               iterator->this_arg_index = iterator->arg_index;
+               iterator->this_arg = iterator->arg;
+               hit = 1;
+
+               /* internally move on the size of this arg */
+               iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+               /*
+                * check for insanity where we are given a bitmap that
+                * claims to have more arg content than the length of the
+                * radiotap section.  We will normally end up equalling this
+                * max_length on the last arg, never exceeding it.
+                */
+
+               if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+                   iterator->max_length)
+                       return -EINVAL;
+
+       next_entry:
+               iterator->arg_index++;
+               if (unlikely((iterator->arg_index & 31) == 0)) {
+                       /* completed current u32 bitmap */
+                       if (iterator->bitmap_shifter & 1) {
+                               /* b31 was set, there is more */
+                               /* move to next u32 bitmap */
+                               iterator->bitmap_shifter = le32_to_cpu(
+                                       get_unaligned(iterator->next_bitmap));
+                               iterator->next_bitmap++;
+                       } else
+                               /* no more bitmaps: end */
+                               iterator->arg_index = sizeof(rt_sizes);
+               } else /* just try the next bit */
+                       iterator->bitmap_shifter >>= 1;
+
+               /* if we found a valid arg earlier, return it now */
+               if (hit)
+                       return 0;
+       }
+
+       /* we don't know how to handle any more args, we're done */
+       return -ENOENT;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);
index 374d16db7315ff3ac9e60f33c9619d7d483a6ecc..2d5d2255a27cd54bb12c1a21724680a5cdba617d 100644 (file)
@@ -39,59 +39,9 @@ static ssize_t _show_permaddr(struct device *dev,
                       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
 }
 
-static ssize_t _store_add_iface(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t len)
-{
-       struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
-       int res;
-
-       if (len > IFNAMSIZ)
-               return -EINVAL;
-
-       if (!rdev->ops->add_virtual_intf)
-               return -ENOSYS;
-
-       rtnl_lock();
-       res = rdev->ops->add_virtual_intf(&rdev->wiphy, (char*)buf,
-                                         NL80211_IFTYPE_UNSPECIFIED);
-       rtnl_unlock();
-
-       return res ? res : len;
-}
-
-static ssize_t _store_remove_iface(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t len)
-{
-       struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
-       int res, ifidx;
-       struct net_device *netdev;
-
-       if (len > IFNAMSIZ)
-               return -EINVAL;
-
-       if (!rdev->ops->del_virtual_intf)
-               return -ENOSYS;
-
-       netdev = dev_get_by_name(buf);
-       if (!netdev)
-               return -ENODEV;
-       ifidx = netdev->ifindex;
-       dev_put(netdev);
-
-       rtnl_lock();
-       res = rdev->ops->del_virtual_intf(&rdev->wiphy, ifidx);
-       rtnl_unlock();
-
-       return res ? res : len;
-}
-
 static struct device_attribute ieee80211_dev_attrs[] = {
        __ATTR(index, S_IRUGO, _show_index, NULL),
        __ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
-       __ATTR(add_iface, S_IWUGO, NULL, _store_add_iface),
-       __ATTR(remove_iface, S_IWUGO, NULL, _store_remove_iface),
        {}
 };
 
@@ -102,12 +52,14 @@ static void wiphy_dev_release(struct device *dev)
        cfg80211_dev_free(rdev);
 }
 
+#ifdef CONFIG_HOTPLUG
 static int wiphy_uevent(struct device *dev, char **envp,
                        int num_envp, char *buf, int size)
 {
        /* TODO, we probably need stuff here */
        return 0;
 }
+#endif
 
 struct class ieee80211_class = {
        .name = "ieee80211",
diff --git a/package/mac80211/src/wireless/wext.c b/package/mac80211/src/wireless/wext.c
deleted file mode 100644 (file)
index d6aaf65..0000000
+++ /dev/null
@@ -1,1509 +0,0 @@
-/*
- * This file implement the Wireless Extensions APIs.
- *
- * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- *
- * (As all part of the Linux kernel, this file is GPL)
- */
-
-/************************** DOCUMENTATION **************************/
-/*
- * API definition :
- * --------------
- * See <linux/wireless.h> for details of the APIs and the rest.
- *
- * History :
- * -------
- *
- * v1 - 5.12.01 - Jean II
- *     o Created this file.
- *
- * v2 - 13.12.01 - Jean II
- *     o Move /proc/net/wireless stuff from net/core/dev.c to here
- *     o Make Wireless Extension IOCTLs go through here
- *     o Added iw_handler handling ;-)
- *     o Added standard ioctl description
- *     o Initial dumb commit strategy based on orinoco.c
- *
- * v3 - 19.12.01 - Jean II
- *     o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
- *     o Add event dispatcher function
- *     o Add event description
- *     o Propagate events as rtnetlink IFLA_WIRELESS option
- *     o Generate event on selected SET requests
- *
- * v4 - 18.04.02 - Jean II
- *     o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- *
- * v5 - 21.06.02 - Jean II
- *     o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
- *     o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- *     o Add IWEVCUSTOM for driver specific event/scanning token
- *     o Turn on WE_STRICT_WRITE by default + kernel warning
- *     o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- *     o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- *
- * v6 - 9.01.03 - Jean II
- *     o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
- *     o Add enhanced spy support : iw_handler_set_thrspy() and event.
- *     o Add WIRELESS_EXT version display in /proc/net/wireless
- *
- * v6 - 18.06.04 - Jean II
- *     o Change get_spydata() method for added safety
- *     o Remove spy #ifdef, they are always on -> cleaner code
- *     o Allow any size GET request if user specifies length > max
- *             and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
- *     o Start migrating get_wireless_stats to struct iw_handler_def
- *     o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
- * Based on patch from Pavel Roskin <proski@gnu.org> :
- *     o Fix kernel data leak to user space in private handler handling
- *
- * v7 - 18.3.05 - Jean II
- *     o Remove (struct iw_point *)->pointer from events and streams
- *     o Remove spy_offset from struct iw_handler_def
- *     o Start deprecating dev->get_wireless_stats, output a warning
- *     o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- *     o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
- *
- * v8 - 17.02.06 - Jean II
- *     o RtNetlink requests support (SET/GET)
- *
- * v8b - 03.08.06 - Herbert Xu
- *     o Fix Wireless Event locking issues.
- *
- * v9 - 14.3.06 - Jean II
- *     o Change length in ESSID and NICK to strlen() instead of strlen()+1
- *     o Make standard_ioctl_num and standard_event_num unsigned
- *     o Remove (struct net_device *)->get_wireless_stats()
- *
- * v10 - 16.3.07 - Jean II
- *     o Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/***************************** INCLUDES *****************************/
-
-#include <linux/module.h>
-#include <linux/types.h>               /* off_t */
-#include <linux/netdevice.h>           /* struct ifreq, dev_get_by_name() */
-#include <linux/proc_fs.h>
-#include <linux/rtnetlink.h>           /* rtnetlink stuff */
-#include <linux/seq_file.h>
-#include <linux/init.h>                        /* for __init */
-#include <linux/if_arp.h>              /* ARPHRD_ETHER */
-#include <linux/etherdevice.h>         /* compare_ether_addr */
-#include <linux/interrupt.h>
-
-#include <linux/wireless.h>            /* Pretty obvious */
-#include <net/iw_handler.h>            /* New driver API */
-#include <net/netlink.h>
-#include <net/wext.h>
-
-#include <asm/uaccess.h>               /* copy_to_user() */
-
-/************************* GLOBAL VARIABLES *************************/
-/*
- * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
-/*
- * Meta-data about all the standard Wireless Extension request we
- * know about.
- */
-static const struct iw_ioctl_description standard_ioctl[] = {
-       [SIOCSIWCOMMIT  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_NULL,
-       },
-       [SIOCGIWNAME    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_CHAR,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWNWID    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-               .flags          = IW_DESCR_FLAG_EVENT,
-       },
-       [SIOCGIWNWID    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWFREQ    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_FREQ,
-               .flags          = IW_DESCR_FLAG_EVENT,
-       },
-       [SIOCGIWFREQ    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_FREQ,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWMODE    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_UINT,
-               .flags          = IW_DESCR_FLAG_EVENT,
-       },
-       [SIOCGIWMODE    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_UINT,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWSENS    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWSENS    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWRANGE   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_NULL,
-       },
-       [SIOCGIWRANGE   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = sizeof(struct iw_range),
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWPRIV    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_NULL,
-       },
-       [SIOCGIWPRIV    - SIOCIWFIRST] = { /* (handled directly by us) */
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct iw_priv_args),
-               .max_tokens     = 16,
-               .flags          = IW_DESCR_FLAG_NOMAX,
-       },
-       [SIOCSIWSTATS   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_NULL,
-       },
-       [SIOCGIWSTATS   - SIOCIWFIRST] = { /* (handled directly by us) */
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = sizeof(struct iw_statistics),
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWSPY     - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct sockaddr),
-               .max_tokens     = IW_MAX_SPY,
-       },
-       [SIOCGIWSPY     - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct sockaddr) +
-                                 sizeof(struct iw_quality),
-               .max_tokens     = IW_MAX_SPY,
-       },
-       [SIOCSIWTHRSPY  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct iw_thrspy),
-               .min_tokens     = 1,
-               .max_tokens     = 1,
-       },
-       [SIOCGIWTHRSPY  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct iw_thrspy),
-               .min_tokens     = 1,
-               .max_tokens     = 1,
-       },
-       [SIOCSIWAP      - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_ADDR,
-       },
-       [SIOCGIWAP      - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_ADDR,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWMLME    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .min_tokens     = sizeof(struct iw_mlme),
-               .max_tokens     = sizeof(struct iw_mlme),
-       },
-       [SIOCGIWAPLIST  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = sizeof(struct sockaddr) +
-                                 sizeof(struct iw_quality),
-               .max_tokens     = IW_MAX_AP,
-               .flags          = IW_DESCR_FLAG_NOMAX,
-       },
-       [SIOCSIWSCAN    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .min_tokens     = 0,
-               .max_tokens     = sizeof(struct iw_scan_req),
-       },
-       [SIOCGIWSCAN    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_SCAN_MAX_DATA,
-               .flags          = IW_DESCR_FLAG_NOMAX,
-       },
-       [SIOCSIWESSID   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ESSID_MAX_SIZE,
-               .flags          = IW_DESCR_FLAG_EVENT,
-       },
-       [SIOCGIWESSID   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ESSID_MAX_SIZE,
-               .flags          = IW_DESCR_FLAG_DUMP,
-       },
-       [SIOCSIWNICKN   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ESSID_MAX_SIZE,
-       },
-       [SIOCGIWNICKN   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ESSID_MAX_SIZE,
-       },
-       [SIOCSIWRATE    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWRATE    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWRTS     - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWRTS     - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWFRAG    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWFRAG    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWTXPOW   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWTXPOW   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWRETRY   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWRETRY   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWENCODE  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ENCODING_TOKEN_MAX,
-               .flags          = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
-       },
-       [SIOCGIWENCODE  - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_ENCODING_TOKEN_MAX,
-               .flags          = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
-       },
-       [SIOCSIWPOWER   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWPOWER   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWGENIE   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_GENERIC_IE_MAX,
-       },
-       [SIOCGIWGENIE   - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_GENERIC_IE_MAX,
-       },
-       [SIOCSIWAUTH    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCGIWAUTH    - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_PARAM,
-       },
-       [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .min_tokens     = sizeof(struct iw_encode_ext),
-               .max_tokens     = sizeof(struct iw_encode_ext) +
-                                 IW_ENCODING_TOKEN_MAX,
-       },
-       [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .min_tokens     = sizeof(struct iw_encode_ext),
-               .max_tokens     = sizeof(struct iw_encode_ext) +
-                                 IW_ENCODING_TOKEN_MAX,
-       },
-       [SIOCSIWPMKSA - SIOCIWFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .min_tokens     = sizeof(struct iw_pmksa),
-               .max_tokens     = sizeof(struct iw_pmksa),
-       },
-};
-static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
-
-/*
- * Meta-data about all the additional standard Wireless Extension events
- * we know about.
- */
-static const struct iw_ioctl_description standard_event[] = {
-       [IWEVTXDROP     - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_ADDR,
-       },
-       [IWEVQUAL       - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_QUAL,
-       },
-       [IWEVCUSTOM     - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_CUSTOM_MAX,
-       },
-       [IWEVREGISTERED - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_ADDR,
-       },
-       [IWEVEXPIRED    - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_ADDR,
-       },
-       [IWEVGENIE      - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_GENERIC_IE_MAX,
-       },
-       [IWEVMICHAELMICFAILURE  - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = sizeof(struct iw_michaelmicfailure),
-       },
-       [IWEVASSOCREQIE - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_GENERIC_IE_MAX,
-       },
-       [IWEVASSOCRESPIE        - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = IW_GENERIC_IE_MAX,
-       },
-       [IWEVPMKIDCAND  - IWEVFIRST] = {
-               .header_type    = IW_HEADER_TYPE_POINT,
-               .token_size     = 1,
-               .max_tokens     = sizeof(struct iw_pmkid_cand),
-       },
-};
-static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
-
-/* Size (in bytes) of the various private data types */
-static const char iw_priv_type_size[] = {
-       0,                              /* IW_PRIV_TYPE_NONE */
-       1,                              /* IW_PRIV_TYPE_BYTE */
-       1,                              /* IW_PRIV_TYPE_CHAR */
-       0,                              /* Not defined */
-       sizeof(__u32),                  /* IW_PRIV_TYPE_INT */
-       sizeof(struct iw_freq),         /* IW_PRIV_TYPE_FLOAT */
-       sizeof(struct sockaddr),        /* IW_PRIV_TYPE_ADDR */
-       0,                              /* Not defined */
-};
-
-/* Size (in bytes) of various events */
-static const int event_type_size[] = {
-       IW_EV_LCP_LEN,                  /* IW_HEADER_TYPE_NULL */
-       0,
-       IW_EV_CHAR_LEN,                 /* IW_HEADER_TYPE_CHAR */
-       0,
-       IW_EV_UINT_LEN,                 /* IW_HEADER_TYPE_UINT */
-       IW_EV_FREQ_LEN,                 /* IW_HEADER_TYPE_FREQ */
-       IW_EV_ADDR_LEN,                 /* IW_HEADER_TYPE_ADDR */
-       0,
-       IW_EV_POINT_LEN,                /* Without variable payload */
-       IW_EV_PARAM_LEN,                /* IW_HEADER_TYPE_PARAM */
-       IW_EV_QUAL_LEN,                 /* IW_HEADER_TYPE_QUAL */
-};
-
-/* Size (in bytes) of various events, as packed */
-static const int event_type_pk_size[] = {
-       IW_EV_LCP_PK_LEN,               /* IW_HEADER_TYPE_NULL */
-       0,
-       IW_EV_CHAR_PK_LEN,              /* IW_HEADER_TYPE_CHAR */
-       0,
-       IW_EV_UINT_PK_LEN,              /* IW_HEADER_TYPE_UINT */
-       IW_EV_FREQ_PK_LEN,              /* IW_HEADER_TYPE_FREQ */
-       IW_EV_ADDR_PK_LEN,              /* IW_HEADER_TYPE_ADDR */
-       0,
-       IW_EV_POINT_PK_LEN,             /* Without variable payload */
-       IW_EV_PARAM_PK_LEN,             /* IW_HEADER_TYPE_PARAM */
-       IW_EV_QUAL_PK_LEN,              /* IW_HEADER_TYPE_QUAL */
-};
-
-/************************ COMMON SUBROUTINES ************************/
-/*
- * Stuff that may be used in various place or doesn't fit in one
- * of the section below.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the driver handler associated with a specific Wireless Extension.
- */
-static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
-{
-       /* Don't "optimise" the following variable, it will crash */
-       unsigned int    index;          /* *MUST* be unsigned */
-
-       /* Check if we have some wireless handlers defined */
-       if (dev->wireless_handlers == NULL)
-               return NULL;
-
-       /* Try as a standard command */
-       index = cmd - SIOCIWFIRST;
-       if (index < dev->wireless_handlers->num_standard)
-               return dev->wireless_handlers->standard[index];
-
-       /* Try as a private command */
-       index = cmd - SIOCIWFIRSTPRIV;
-       if (index < dev->wireless_handlers->num_private)
-               return dev->wireless_handlers->private[index];
-
-       /* Not found */
-       return NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Get statistics out of the driver
- */
-static struct iw_statistics *get_wireless_stats(struct net_device *dev)
-{
-       /* New location */
-       if ((dev->wireless_handlers != NULL) &&
-          (dev->wireless_handlers->get_wireless_stats != NULL))
-               return dev->wireless_handlers->get_wireless_stats(dev);
-
-       /* Not found */
-       return NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call the commit handler in the driver
- * (if exist and if conditions are right)
- *
- * Note : our current commit strategy is currently pretty dumb,
- * but we will be able to improve on that...
- * The goal is to try to agreagate as many changes as possible
- * before doing the commit. Drivers that will define a commit handler
- * are usually those that need a reset after changing parameters, so
- * we want to minimise the number of reset.
- * A cool idea is to use a timer : at each "set" command, we re-set the
- * timer, when the timer eventually fires, we call the driver.
- * Hopefully, more on that later.
- *
- * Also, I'm waiting to see how many people will complain about the
- * netif_running(dev) test. I'm open on that one...
- * Hopefully, the driver will remember to do a commit in "open()" ;-)
- */
-static int call_commit_handler(struct net_device *dev)
-{
-       if ((netif_running(dev)) &&
-          (dev->wireless_handlers->standard[0] != NULL))
-               /* Call the commit handler on the driver */
-               return dev->wireless_handlers->standard[0](dev, NULL,
-                                                          NULL, NULL);
-       else
-               return 0;               /* Command completed successfully */
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Calculate size of private arguments
- */
-static inline int get_priv_size(__u16  args)
-{
-       int     num = args & IW_PRIV_SIZE_MASK;
-       int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
-
-       return num * iw_priv_type_size[type];
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Re-calculate the size of private arguments
- */
-static inline int adjust_priv_size(__u16               args,
-                                  union iwreq_data *   wrqu)
-{
-       int     num = wrqu->data.length;
-       int     max = args & IW_PRIV_SIZE_MASK;
-       int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
-
-       /* Make sure the driver doesn't goof up */
-       if (max < num)
-               num = max;
-
-       return num * iw_priv_type_size[type];
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get wireless stats
- *     Allow programatic access to /proc/net/wireless even if /proc
- *     doesn't exist... Also more efficient...
- */
-static int iw_handler_get_iwstats(struct net_device *          dev,
-                                 struct iw_request_info *      info,
-                                 union iwreq_data *            wrqu,
-                                 char *                        extra)
-{
-       /* Get stats from the driver */
-       struct iw_statistics *stats;
-
-       stats = get_wireless_stats(dev);
-       if (stats) {
-               /* Copy statistics to extra */
-               memcpy(extra, stats, sizeof(struct iw_statistics));
-               wrqu->data.length = sizeof(struct iw_statistics);
-
-               /* Check if we need to clear the updated flag */
-               if (wrqu->data.flags != 0)
-                       stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
-               return 0;
-       } else
-               return -EOPNOTSUPP;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get iwpriv definitions
- * Export the driver private handler definition
- * They will be picked up by tools like iwpriv...
- */
-static int iw_handler_get_private(struct net_device *          dev,
-                                 struct iw_request_info *      info,
-                                 union iwreq_data *            wrqu,
-                                 char *                        extra)
-{
-       /* Check if the driver has something to export */
-       if ((dev->wireless_handlers->num_private_args == 0) ||
-          (dev->wireless_handlers->private_args == NULL))
-               return -EOPNOTSUPP;
-
-       /* Check if there is enough buffer up there */
-       if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
-               /* User space can't know in advance how large the buffer
-                * needs to be. Give it a hint, so that we can support
-                * any size buffer we want somewhat efficiently... */
-               wrqu->data.length = dev->wireless_handlers->num_private_args;
-               return -E2BIG;
-       }
-
-       /* Set the number of available ioctls. */
-       wrqu->data.length = dev->wireless_handlers->num_private_args;
-
-       /* Copy structure to the user buffer. */
-       memcpy(extra, dev->wireless_handlers->private_args,
-              sizeof(struct iw_priv_args) * wrqu->data.length);
-
-       return 0;
-}
-
-
-/******************** /proc/net/wireless SUPPORT ********************/
-/*
- * The /proc/net/wireless file is a human readable user-space interface
- * exporting various wireless specific statistics from the wireless devices.
- * This is the most popular part of the Wireless Extensions ;-)
- *
- * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
- * The content of the file is basically the content of "struct iw_statistics".
- */
-
-#ifdef CONFIG_PROC_FS
-
-/* ---------------------------------------------------------------- */
-/*
- * Print one entry (line) of /proc/net/wireless
- */
-static void wireless_seq_printf_stats(struct seq_file *seq,
-                                     struct net_device *dev)
-{
-       /* Get stats from the driver */
-       struct iw_statistics *stats = get_wireless_stats(dev);
-
-       if (stats) {
-               seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
-                               "%6d %6d   %6d\n",
-                          dev->name, stats->status, stats->qual.qual,
-                          stats->qual.updated & IW_QUAL_QUAL_UPDATED
-                          ? '.' : ' ',
-                          ((__s32) stats->qual.level) -
-                          ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-                          stats->qual.updated & IW_QUAL_LEVEL_UPDATED
-                          ? '.' : ' ',
-                          ((__s32) stats->qual.noise) -
-                          ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-                          stats->qual.updated & IW_QUAL_NOISE_UPDATED
-                          ? '.' : ' ',
-                          stats->discard.nwid, stats->discard.code,
-                          stats->discard.fragment, stats->discard.retries,
-                          stats->discard.misc, stats->miss.beacon);
-               stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
-       }
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Print info for /proc/net/wireless (print all entries)
- */
-static int wireless_seq_show(struct seq_file *seq, void *v)
-{
-       if (v == SEQ_START_TOKEN)
-               seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
-                               "packets               | Missed | WE\n"
-                               " face | tus | link level noise |  nwid  "
-                               "crypt   frag  retry   misc | beacon | %d\n",
-                          WIRELESS_EXT);
-       else
-               wireless_seq_printf_stats(seq, v);
-       return 0;
-}
-
-static const struct seq_operations wireless_seq_ops = {
-       .start = dev_seq_start,
-       .next  = dev_seq_next,
-       .stop  = dev_seq_stop,
-       .show  = wireless_seq_show,
-};
-
-static int wireless_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &wireless_seq_ops);
-}
-
-static const struct file_operations wireless_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = wireless_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-int __init wext_proc_init(void)
-{
-       /* Create /proc/net/wireless entry */
-       if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
-               return -ENOMEM;
-
-       return 0;
-}
-#endif /* CONFIG_PROC_FS */
-
-/************************** IOCTL SUPPORT **************************/
-/*
- * The original user space API to configure all those Wireless Extensions
- * is through IOCTLs.
- * In there, we check if we need to call the new driver API (iw_handler)
- * or just call the driver ioctl handler.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a standard Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- */
-static int ioctl_standard_call(struct net_device *     dev,
-                              struct ifreq *           ifr,
-                              unsigned int             cmd,
-                              iw_handler               handler)
-{
-       struct iwreq *                          iwr = (struct iwreq *) ifr;
-       const struct iw_ioctl_description *     descr;
-       struct iw_request_info                  info;
-       int                                     ret = -EINVAL;
-
-       /* Get the description of the IOCTL */
-       if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-               return -EOPNOTSUPP;
-       descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
-       /* Prepare the call */
-       info.cmd = cmd;
-       info.flags = 0;
-
-       /* Check if we have a pointer to user space data or not */
-       if (descr->header_type != IW_HEADER_TYPE_POINT) {
-
-               /* No extra arguments. Trivial to handle */
-               ret = handler(dev, &info, &(iwr->u), NULL);
-
-               /* Generate an event to notify listeners of the change */
-               if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
-                  ((ret == 0) || (ret == -EIWCOMMIT)))
-                       wireless_send_event(dev, cmd, &(iwr->u), NULL);
-       } else {
-               char *  extra;
-               int     extra_size;
-               int     user_length = 0;
-               int     err;
-               int     essid_compat = 0;
-
-               /* Calculate space needed by arguments. Always allocate
-                * for max space. Easier, and won't last long... */
-               extra_size = descr->max_tokens * descr->token_size;
-
-               /* Check need for ESSID compatibility for WE < 21 */
-               switch (cmd) {
-               case SIOCSIWESSID:
-               case SIOCGIWESSID:
-               case SIOCSIWNICKN:
-               case SIOCGIWNICKN:
-                       if (iwr->u.data.length == descr->max_tokens + 1)
-                               essid_compat = 1;
-                       else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                               char essid[IW_ESSID_MAX_SIZE + 1];
-
-                               err = copy_from_user(essid, iwr->u.data.pointer,
-                                                    iwr->u.data.length *
-                                                    descr->token_size);
-                               if (err)
-                                       return -EFAULT;
-
-                               if (essid[iwr->u.data.length - 1] == '\0')
-                                       essid_compat = 1;
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               iwr->u.data.length -= essid_compat;
-
-               /* Check what user space is giving us */
-               if (IW_IS_SET(cmd)) {
-                       /* Check NULL pointer */
-                       if ((iwr->u.data.pointer == NULL) &&
-                          (iwr->u.data.length != 0))
-                               return -EFAULT;
-                       /* Check if number of token fits within bounds */
-                       if (iwr->u.data.length > descr->max_tokens)
-                               return -E2BIG;
-                       if (iwr->u.data.length < descr->min_tokens)
-                               return -EINVAL;
-               } else {
-                       /* Check NULL pointer */
-                       if (iwr->u.data.pointer == NULL)
-                               return -EFAULT;
-                       /* Save user space buffer size for checking */
-                       user_length = iwr->u.data.length;
-
-                       /* Don't check if user_length > max to allow forward
-                        * compatibility. The test user_length < min is
-                        * implied by the test at the end. */
-
-                       /* Support for very large requests */
-                       if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
-                          (user_length > descr->max_tokens)) {
-                               /* Allow userspace to GET more than max so
-                                * we can support any size GET requests.
-                                * There is still a limit : -ENOMEM. */
-                               extra_size = user_length * descr->token_size;
-                               /* Note : user_length is originally a __u16,
-                                * and token_size is controlled by us,
-                                * so extra_size won't get negative and
-                                * won't overflow... */
-                       }
-               }
-
-               /* Create the kernel buffer */
-               /*    kzalloc ensures NULL-termination for essid_compat */
-               extra = kzalloc(extra_size, GFP_KERNEL);
-               if (extra == NULL)
-                       return -ENOMEM;
-
-               /* If it is a SET, get all the extra data in here */
-               if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                       err = copy_from_user(extra, iwr->u.data.pointer,
-                                            iwr->u.data.length *
-                                            descr->token_size);
-                       if (err) {
-                               kfree(extra);
-                               return -EFAULT;
-                       }
-               }
-
-               /* Call the handler */
-               ret = handler(dev, &info, &(iwr->u), extra);
-
-               iwr->u.data.length += essid_compat;
-
-               /* If we have something to return to the user */
-               if (!ret && IW_IS_GET(cmd)) {
-                       /* Check if there is enough buffer up there */
-                       if (user_length < iwr->u.data.length) {
-                               kfree(extra);
-                               return -E2BIG;
-                       }
-
-                       err = copy_to_user(iwr->u.data.pointer, extra,
-                                          iwr->u.data.length *
-                                          descr->token_size);
-                       if (err)
-                               ret =  -EFAULT;
-               }
-
-               /* Generate an event to notify listeners of the change */
-               if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
-                  ((ret == 0) || (ret == -EIWCOMMIT))) {
-                       if (descr->flags & IW_DESCR_FLAG_RESTRICT)
-                               /* If the event is restricted, don't
-                                * export the payload */
-                               wireless_send_event(dev, cmd, &(iwr->u), NULL);
-                       else
-                               wireless_send_event(dev, cmd, &(iwr->u),
-                                                   extra);
-               }
-
-               /* Cleanup - I told you it wasn't that long ;-) */
-               kfree(extra);
-       }
-
-       /* Call commit handler if needed and defined */
-       if (ret == -EIWCOMMIT)
-               ret = call_commit_handler(dev);
-
-       /* Here, we will generate the appropriate event if needed */
-
-       return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
- *
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
- */
-static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
-                             unsigned int cmd, iw_handler handler)
-{
-       struct iwreq *                  iwr = (struct iwreq *) ifr;
-       const struct iw_priv_args *     descr = NULL;
-       struct iw_request_info          info;
-       int                             extra_size = 0;
-       int                             i;
-       int                             ret = -EINVAL;
-
-       /* Get the description of the IOCTL */
-       for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
-               if (cmd == dev->wireless_handlers->private_args[i].cmd) {
-                       descr = &(dev->wireless_handlers->private_args[i]);
-                       break;
-               }
-
-       /* Compute the size of the set/get arguments */
-       if (descr != NULL) {
-               if (IW_IS_SET(cmd)) {
-                       int     offset = 0;     /* For sub-ioctls */
-                       /* Check for sub-ioctl handler */
-                       if (descr->name[0] == '\0')
-                               /* Reserve one int for sub-ioctl index */
-                               offset = sizeof(__u32);
-
-                       /* Size of set arguments */
-                       extra_size = get_priv_size(descr->set_args);
-
-                       /* Does it fits in iwr ? */
-                       if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-                          ((extra_size + offset) <= IFNAMSIZ))
-                               extra_size = 0;
-               } else {
-                       /* Size of get arguments */
-                       extra_size = get_priv_size(descr->get_args);
-
-                       /* Does it fits in iwr ? */
-                       if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-                          (extra_size <= IFNAMSIZ))
-                               extra_size = 0;
-               }
-       }
-
-       /* Prepare the call */
-       info.cmd = cmd;
-       info.flags = 0;
-
-       /* Check if we have a pointer to user space data or not. */
-       if (extra_size == 0) {
-               /* No extra arguments. Trivial to handle */
-               ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
-       } else {
-               char *  extra;
-               int     err;
-
-               /* Check what user space is giving us */
-               if (IW_IS_SET(cmd)) {
-                       /* Check NULL pointer */
-                       if ((iwr->u.data.pointer == NULL) &&
-                          (iwr->u.data.length != 0))
-                               return -EFAULT;
-
-                       /* Does it fits within bounds ? */
-                       if (iwr->u.data.length > (descr->set_args &
-                                                IW_PRIV_SIZE_MASK))
-                               return -E2BIG;
-               } else if (iwr->u.data.pointer == NULL)
-                       return -EFAULT;
-
-               /* Always allocate for max space. Easier, and won't last
-                * long... */
-               extra = kmalloc(extra_size, GFP_KERNEL);
-               if (extra == NULL)
-                       return -ENOMEM;
-
-               /* If it is a SET, get all the extra data in here */
-               if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-                       err = copy_from_user(extra, iwr->u.data.pointer,
-                                            extra_size);
-                       if (err) {
-                               kfree(extra);
-                               return -EFAULT;
-                       }
-               }
-
-               /* Call the handler */
-               ret = handler(dev, &info, &(iwr->u), extra);
-
-               /* If we have something to return to the user */
-               if (!ret && IW_IS_GET(cmd)) {
-
-                       /* Adjust for the actual length if it's variable,
-                        * avoid leaking kernel bits outside. */
-                       if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
-                               extra_size = adjust_priv_size(descr->get_args,
-                                                             &(iwr->u));
-                       }
-
-                       err = copy_to_user(iwr->u.data.pointer, extra,
-                                          extra_size);
-                       if (err)
-                               ret =  -EFAULT;
-               }
-
-               /* Cleanup - I told you it wasn't that long ;-) */
-               kfree(extra);
-       }
-
-
-       /* Call commit handler if needed and defined */
-       if (ret == -EIWCOMMIT)
-               ret = call_commit_handler(dev);
-
-       return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Main IOCTl dispatcher.
- * Check the type of IOCTL and call the appropriate wrapper...
- */
-static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
-{
-       struct net_device *dev;
-       iw_handler      handler;
-
-       /* Permissions are already checked in dev_ioctl() before calling us.
-        * The copy_to/from_user() of ifr is also dealt with in there */
-
-       /* Make sure the device exist */
-       if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
-               return -ENODEV;
-
-       /* A bunch of special cases, then the generic case...
-        * Note that 'cmd' is already filtered in dev_ioctl() with
-        * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
-       if (cmd == SIOCGIWSTATS)
-               return ioctl_standard_call(dev, ifr, cmd,
-                                          &iw_handler_get_iwstats);
-
-       if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
-               return ioctl_standard_call(dev, ifr, cmd,
-                                          &iw_handler_get_private);
-
-       /* Basic check */
-       if (!netif_device_present(dev))
-               return -ENODEV;
-
-       /* New driver API : try to find the handler */
-       handler = get_handler(dev, cmd);
-       if (handler) {
-               /* Standard and private are not the same */
-               if (cmd < SIOCIWFIRSTPRIV)
-                       return ioctl_standard_call(dev, ifr, cmd, handler);
-               else
-                       return ioctl_private_call(dev, ifr, cmd, handler);
-       }
-       /* Old driver API : call driver ioctl handler */
-       if (dev->do_ioctl)
-               return dev->do_ioctl(dev, ifr, cmd);
-       return -EOPNOTSUPP;
-}
-
-/* entry point from dev ioctl */
-int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
-                     void __user *arg)
-{
-       int ret;
-
-       /* If command is `set a parameter', or
-        * `get the encoding parameters', check if
-        * the user has the right to do it */
-       if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
-           && !capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       dev_load(ifr->ifr_name);
-       rtnl_lock();
-       ret = wireless_process_ioctl(ifr, cmd);
-       rtnl_unlock();
-       if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct ifreq)))
-               return -EFAULT;
-       return ret;
-}
-
-/************************* EVENT PROCESSING *************************/
-/*
- * Process events generated by the wireless layer or the driver.
- * Most often, the event will be propagated through rtnetlink
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Locking...
- * ----------
- *
- * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
- * the locking issue in here and implementing this code !
- *
- * The issue : wireless_send_event() is often called in interrupt context,
- * while the Netlink layer can never be called in interrupt context.
- * The fully formed RtNetlink events are queued, and then a tasklet is run
- * to feed those to Netlink.
- * The skb_queue is interrupt safe, and its lock is not held while calling
- * Netlink, so there is no possibility of dealock.
- * Jean II
- */
-
-static struct sk_buff_head wireless_nlevent_queue;
-
-static int __init wireless_nlevent_init(void)
-{
-       skb_queue_head_init(&wireless_nlevent_queue);
-       return 0;
-}
-
-subsys_initcall(wireless_nlevent_init);
-
-static void wireless_nlevent_process(unsigned long data)
-{
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&wireless_nlevent_queue)))
-               rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
-}
-
-static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
-
-/* ---------------------------------------------------------------- */
-/*
- * Fill a rtnetlink message with our event data.
- * Note that we propage only the specified event and don't dump the
- * current wireless config. Dumping the wireless config is far too
- * expensive (for each parameter, the driver need to query the hardware).
- */
-static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
-                                int type, char *event, int event_len)
-{
-       struct ifinfomsg *r;
-       struct nlmsghdr  *nlh;
-       unsigned char    *b = skb_tail_pointer(skb);
-
-       nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
-       r = NLMSG_DATA(nlh);
-       r->ifi_family = AF_UNSPEC;
-       r->__ifi_pad = 0;
-       r->ifi_type = dev->type;
-       r->ifi_index = dev->ifindex;
-       r->ifi_flags = dev_get_flags(dev);
-       r->ifi_change = 0;      /* Wireless changes don't affect those flags */
-
-       /* Add the wireless events in the netlink packet */
-       RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
-
-       nlh->nlmsg_len = skb_tail_pointer(skb) - b;
-       return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-       nlmsg_trim(skb, b);
-       return -1;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Create and broadcast and send it on the standard rtnetlink socket
- * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
- * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
- * within a RTM_NEWLINK event.
- */
-static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
-{
-       struct sk_buff *skb;
-       int size = NLMSG_GOODSIZE;
-
-       skb = alloc_skb(size, GFP_ATOMIC);
-       if (!skb)
-               return;
-
-       if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
-                                 event, event_len) < 0) {
-               kfree_skb(skb);
-               return;
-       }
-       NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
-       skb_queue_tail(&wireless_nlevent_queue, skb);
-       tasklet_schedule(&wireless_nlevent_tasklet);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Main event dispatcher. Called from other parts and drivers.
- * Send the event on the appropriate channels.
- * May be called from interrupt context.
- */
-void wireless_send_event(struct net_device *   dev,
-                        unsigned int           cmd,
-                        union iwreq_data *     wrqu,
-                        char *                 extra)
-{
-       const struct iw_ioctl_description *     descr = NULL;
-       int extra_len = 0;
-       struct iw_event  *event;                /* Mallocated whole event */
-       int event_len;                          /* Its size */
-       int hdr_len;                            /* Size of the event header */
-       int wrqu_off = 0;                       /* Offset in wrqu */
-       /* Don't "optimise" the following variable, it will crash */
-       unsigned        cmd_index;              /* *MUST* be unsigned */
-
-       /* Get the description of the Event */
-       if (cmd <= SIOCIWLAST) {
-               cmd_index = cmd - SIOCIWFIRST;
-               if (cmd_index < standard_ioctl_num)
-                       descr = &(standard_ioctl[cmd_index]);
-       } else {
-               cmd_index = cmd - IWEVFIRST;
-               if (cmd_index < standard_event_num)
-                       descr = &(standard_event[cmd_index]);
-       }
-       /* Don't accept unknown events */
-       if (descr == NULL) {
-               /* Note : we don't return an error to the driver, because
-                * the driver would not know what to do about it. It can't
-                * return an error to the user, because the event is not
-                * initiated by a user request.
-                * The best the driver could do is to log an error message.
-                * We will do it ourselves instead...
-                */
-               printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
-                      dev->name, cmd);
-               return;
-       }
-
-       /* Check extra parameters and set extra_len */
-       if (descr->header_type == IW_HEADER_TYPE_POINT) {
-               /* Check if number of token fits within bounds */
-               if (wrqu->data.length > descr->max_tokens) {
-                       printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
-                       return;
-               }
-               if (wrqu->data.length < descr->min_tokens) {
-                       printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
-                       return;
-               }
-               /* Calculate extra_len - extra is NULL for restricted events */
-               if (extra != NULL)
-                       extra_len = wrqu->data.length * descr->token_size;
-               /* Always at an offset in wrqu */
-               wrqu_off = IW_EV_POINT_OFF;
-       }
-
-       /* Total length of the event */
-       hdr_len = event_type_size[descr->header_type];
-       event_len = hdr_len + extra_len;
-
-       /* Create temporary buffer to hold the event */
-       event = kmalloc(event_len, GFP_ATOMIC);
-       if (event == NULL)
-               return;
-
-       /* Fill event */
-       event->len = event_len;
-       event->cmd = cmd;
-       memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
-       if (extra)
-               memcpy(((char *) event) + hdr_len, extra, extra_len);
-
-       /* Send via the RtNetlink event channel */
-       rtmsg_iwinfo(dev, (char *) event, event_len);
-
-       /* Cleanup */
-       kfree(event);
-
-       return;         /* Always success, I guess ;-) */
-}
-EXPORT_SYMBOL(wireless_send_event);
-
-/********************** ENHANCED IWSPY SUPPORT **********************/
-/*
- * In the old days, the driver was handling spy support all by itself.
- * Now, the driver can delegate this task to Wireless Extensions.
- * It needs to use those standard spy iw_handler in struct iw_handler_def,
- * push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and export it in net_device->wireless_data->spy_data).
- * One of the main advantage of centralising spy support here is that
- * it becomes much easier to improve and extend it without having to touch
- * the drivers. One example is the addition of the Spy-Threshold events.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the pointer to the spy data in the driver.
- * Because this is called on the Rx path via wireless_spy_update(),
- * we want it to be efficient...
- */
-static inline struct iw_spy_data *get_spydata(struct net_device *dev)
-{
-       /* This is the new way */
-       if (dev->wireless_data)
-               return dev->wireless_data->spy_data;
-       return NULL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set Spy List
- */
-int iw_handler_set_spy(struct net_device *     dev,
-                      struct iw_request_info * info,
-                      union iwreq_data *       wrqu,
-                      char *                   extra)
-{
-       struct iw_spy_data *    spydata = get_spydata(dev);
-       struct sockaddr *       address = (struct sockaddr *) extra;
-
-       /* Make sure driver is not buggy or using the old API */
-       if (!spydata)
-               return -EOPNOTSUPP;
-
-       /* Disable spy collection while we copy the addresses.
-        * While we copy addresses, any call to wireless_spy_update()
-        * will NOP. This is OK, as anyway the addresses are changing. */
-       spydata->spy_number = 0;
-
-       /* We want to operate without locking, because wireless_spy_update()
-        * most likely will happen in the interrupt handler, and therefore
-        * have its own locking constraints and needs performance.
-        * The rtnl_lock() make sure we don't race with the other iw_handlers.
-        * This make sure wireless_spy_update() "see" that the spy list
-        * is temporarily disabled. */
-       smp_wmb();
-
-       /* Are there are addresses to copy? */
-       if (wrqu->data.length > 0) {
-               int i;
-
-               /* Copy addresses */
-               for (i = 0; i < wrqu->data.length; i++)
-                       memcpy(spydata->spy_address[i], address[i].sa_data,
-                              ETH_ALEN);
-               /* Reset stats */
-               memset(spydata->spy_stat, 0,
-                      sizeof(struct iw_quality) * IW_MAX_SPY);
-       }
-
-       /* Make sure above is updated before re-enabling */
-       smp_wmb();
-
-       /* Enable addresses */
-       spydata->spy_number = wrqu->data.length;
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get Spy List
- */
-int iw_handler_get_spy(struct net_device *     dev,
-                      struct iw_request_info * info,
-                      union iwreq_data *       wrqu,
-                      char *                   extra)
-{
-       struct iw_spy_data *    spydata = get_spydata(dev);
-       struct sockaddr *       address = (struct sockaddr *) extra;
-       int                     i;
-
-       /* Make sure driver is not buggy or using the old API */
-       if (!spydata)
-               return -EOPNOTSUPP;
-
-       wrqu->data.length = spydata->spy_number;
-
-       /* Copy addresses. */
-       for (i = 0; i < spydata->spy_number; i++)       {
-               memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
-               address[i].sa_family = AF_UNIX;
-       }
-       /* Copy stats to the user buffer (just after). */
-       if (spydata->spy_number > 0)
-               memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
-                      spydata->spy_stat,
-                      sizeof(struct iw_quality) * spydata->spy_number);
-       /* Reset updated flags. */
-       for (i = 0; i < spydata->spy_number; i++)
-               spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set spy threshold
- */
-int iw_handler_set_thrspy(struct net_device *  dev,
-                         struct iw_request_info *info,
-                         union iwreq_data *    wrqu,
-                         char *                extra)
-{
-       struct iw_spy_data *    spydata = get_spydata(dev);
-       struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
-
-       /* Make sure driver is not buggy or using the old API */
-       if (!spydata)
-               return -EOPNOTSUPP;
-
-       /* Just do it */
-       memcpy(&(spydata->spy_thr_low), &(threshold->low),
-              2 * sizeof(struct iw_quality));
-
-       /* Clear flag */
-       memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get spy threshold
- */
-int iw_handler_get_thrspy(struct net_device *  dev,
-                         struct iw_request_info *info,
-                         union iwreq_data *    wrqu,
-                         char *                extra)
-{
-       struct iw_spy_data *    spydata = get_spydata(dev);
-       struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
-
-       /* Make sure driver is not buggy or using the old API */
-       if (!spydata)
-               return -EOPNOTSUPP;
-
-       /* Just do it */
-       memcpy(&(threshold->low), &(spydata->spy_thr_low),
-              2 * sizeof(struct iw_quality));
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare and send a Spy Threshold event
- */
-static void iw_send_thrspy_event(struct net_device *   dev,
-                                struct iw_spy_data *   spydata,
-                                unsigned char *        address,
-                                struct iw_quality *    wstats)
-{
-       union iwreq_data        wrqu;
-       struct iw_thrspy        threshold;
-
-       /* Init */
-       wrqu.data.length = 1;
-       wrqu.data.flags = 0;
-       /* Copy address */
-       memcpy(threshold.addr.sa_data, address, ETH_ALEN);
-       threshold.addr.sa_family = ARPHRD_ETHER;
-       /* Copy stats */
-       memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
-       /* Copy also thresholds */
-       memcpy(&(threshold.low), &(spydata->spy_thr_low),
-              2 * sizeof(struct iw_quality));
-
-       /* Send event to user space */
-       wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call for the driver to update the spy data.
- * For now, the spy data is a simple array. As the size of the array is
- * small, this is good enough. If we wanted to support larger number of
- * spy addresses, we should use something more efficient...
- */
-void wireless_spy_update(struct net_device *   dev,
-                        unsigned char *        address,
-                        struct iw_quality *    wstats)
-{
-       struct iw_spy_data *    spydata = get_spydata(dev);
-       int                     i;
-       int                     match = -1;
-
-       /* Make sure driver is not buggy or using the old API */
-       if (!spydata)
-               return;
-
-       /* Update all records that match */
-       for (i = 0; i < spydata->spy_number; i++)
-               if (!compare_ether_addr(address, spydata->spy_address[i])) {
-                       memcpy(&(spydata->spy_stat[i]), wstats,
-                              sizeof(struct iw_quality));
-                       match = i;
-               }
-
-       /* Generate an event if we cross the spy threshold.
-        * To avoid event storms, we have a simple hysteresis : we generate
-        * event only when we go under the low threshold or above the
-        * high threshold. */
-       if (match >= 0) {
-               if (spydata->spy_thr_under[match]) {
-                       if (wstats->level > spydata->spy_thr_high.level) {
-                               spydata->spy_thr_under[match] = 0;
-                               iw_send_thrspy_event(dev, spydata,
-                                                    address, wstats);
-                       }
-               } else {
-                       if (wstats->level < spydata->spy_thr_low.level) {
-                               spydata->spy_thr_under[match] = 1;
-                               iw_send_thrspy_event(dev, spydata,
-                                                    address, wstats);
-                       }
-               }
-       }
-}
-EXPORT_SYMBOL(wireless_spy_update);