Upgrade b43 and mac80211.
authorMichael Büsch <mb@bu3sch.de>
Fri, 15 Feb 2008 22:47:47 +0000 (22:47 +0000)
committerMichael Büsch <mb@bu3sch.de>
Fri, 15 Feb 2008 22:47:47 +0000 (22:47 +0000)
This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211.
Will do that in a seperate patch.

SVN-Revision: 10466

103 files changed:
package/b43/Makefile
package/b43/src/Kconfig
package/b43/src/Makefile
package/b43/src/b43.h
package/b43/src/debugfs.c
package/b43/src/dma.c
package/b43/src/dma.h
package/b43/src/leds.c
package/b43/src/lo.c
package/b43/src/main.c
package/b43/src/main.h
package/b43/src/nphy.c [new file with mode: 0644]
package/b43/src/nphy.h [new file with mode: 0644]
package/b43/src/pcmcia.c
package/b43/src/phy.c
package/b43/src/phy.h
package/b43/src/pio.c [deleted file]
package/b43/src/pio.h [deleted file]
package/b43/src/rfkill.c
package/b43/src/rfkill.h
package/b43/src/sysfs.c
package/b43/src/tables.c
package/b43/src/tables.h
package/b43/src/tables_nphy.c [new file with mode: 0644]
package/b43/src/tables_nphy.h [new file with mode: 0644]
package/b43/src/wa.c [new file with mode: 0644]
package/b43/src/wa.h [new file with mode: 0644]
package/b43/src/xmit.c
package/b43/src/xmit.h
package/hostapd/files/default.config
package/hostapd/files/mini.config
package/mac80211/Makefile
package/mac80211/patches/000-mac80211_update.patch [deleted file]
package/mac80211/patches/001-port-to-2.6.23.patch [new file with mode: 0644]
package/mac80211/patches/008-add-hostapd-ioctl-header.patch [deleted file]
package/mac80211/patches/009-add-old-ioctl-skeleton.patch [deleted file]
package/mac80211/patches/010-add-mgmt-iface.patch [deleted file]
package/mac80211/patches/011-allow-ap-vlan-modes.patch [deleted file]
package/mac80211/patches/012-mac80211-allow-wds.patch [deleted file]
package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch [deleted file]
package/mac80211/patches/014-prism2-ioctl-8021x.patch [deleted file]
package/mac80211/patches/015-hostapd-ioctl-hw-features.patch [deleted file]
package/mac80211/patches/016-prism2-ioctl-eapol.patch [deleted file]
package/mac80211/patches/017-nl80211-add-key-mgmt.patch [deleted file]
package/mac80211/patches/018-mac80211-cfg80211-keys.patch [deleted file]
package/mac80211/patches/019-mac80211-key-seq-nl80211.patch [deleted file]
package/mac80211/patches/020-nl80211-beacon-parameters.patch [deleted file]
package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch [deleted file]
package/mac80211/patches/022-nl80211-sta.patch [deleted file]
package/mac80211/patches/023-mac80211-implement-sta.patch [deleted file]
package/mac80211/patches/024-nl80211-get-sta.patch [deleted file]
package/mac80211/patches/025-mac80211-get-sta.patch [deleted file]
package/mac80211/src/include/linux/ieee80211.h
package/mac80211/src/include/linux/nl80211.h
package/mac80211/src/include/net/cfg80211.h
package/mac80211/src/include/net/mac80211.h
package/mac80211/src/include/net/wireless.h [new file with mode: 0644]
package/mac80211/src/net/mac80211/Kconfig
package/mac80211/src/net/mac80211/Makefile
package/mac80211/src/net/mac80211/aes_ccm.c
package/mac80211/src/net/mac80211/cfg.c
package/mac80211/src/net/mac80211/debugfs.c
package/mac80211/src/net/mac80211/debugfs_key.c
package/mac80211/src/net/mac80211/debugfs_netdev.c
package/mac80211/src/net/mac80211/debugfs_sta.c
package/mac80211/src/net/mac80211/event.c
package/mac80211/src/net/mac80211/ieee80211.c
package/mac80211/src/net/mac80211/ieee80211_common.h [deleted file]
package/mac80211/src/net/mac80211/ieee80211_i.h
package/mac80211/src/net/mac80211/ieee80211_iface.c
package/mac80211/src/net/mac80211/ieee80211_ioctl.c
package/mac80211/src/net/mac80211/ieee80211_led.c
package/mac80211/src/net/mac80211/ieee80211_led.h
package/mac80211/src/net/mac80211/ieee80211_rate.c
package/mac80211/src/net/mac80211/ieee80211_rate.h
package/mac80211/src/net/mac80211/ieee80211_sta.c
package/mac80211/src/net/mac80211/key.c
package/mac80211/src/net/mac80211/rc80211_pid.h [new file with mode: 0644]
package/mac80211/src/net/mac80211/rc80211_pid_algo.c [new file with mode: 0644]
package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c [new file with mode: 0644]
package/mac80211/src/net/mac80211/rc80211_simple.c
package/mac80211/src/net/mac80211/regdomain.c [deleted file]
package/mac80211/src/net/mac80211/rx.c
package/mac80211/src/net/mac80211/sta_info.c
package/mac80211/src/net/mac80211/sta_info.h
package/mac80211/src/net/mac80211/tkip.c
package/mac80211/src/net/mac80211/tx.c
package/mac80211/src/net/mac80211/util.c
package/mac80211/src/net/mac80211/wep.c
package/mac80211/src/net/mac80211/wep.h
package/mac80211/src/net/mac80211/wme.c
package/mac80211/src/net/mac80211/wme.h
package/mac80211/src/net/mac80211/wpa.c
package/mac80211/src/net/mac80211/wpa.h
package/mac80211/src/net/wireless/Kconfig
package/mac80211/src/net/wireless/Makefile
package/mac80211/src/net/wireless/core.c
package/mac80211/src/net/wireless/core.h
package/mac80211/src/net/wireless/nl80211.c
package/mac80211/src/net/wireless/reg.c [new file with mode: 0644]
package/mac80211/src/net/wireless/sysfs.c
package/mac80211/src/net/wireless/util.c [new file with mode: 0644]
package/mac80211/src/net/wireless/wext.c [new file with mode: 0644]

index c4cc91f5cfbd0360f72619be795bf7d6e3ac8d1c..e47d5165ebf6b5aba882d26c9aad58948f034e1a 100644 (file)
@@ -23,11 +23,11 @@ PKG_FWV4_SOURCE_URL:=http://downloads.openwrt.org/sources/
 PKG_FWV4_MD5SUM:=a7d8dde3ce474c361143b83e1d9890b1
 
 PKG_FWCUTTER_NAME:=b43-fwcutter
-PKG_FWCUTTER_VERSION=008
+PKG_FWCUTTER_VERSION=011
 
 PKG_FWCUTTER_SOURCE:=$(PKG_FWCUTTER_NAME)-$(PKG_FWCUTTER_VERSION).tar.bz2
-PKG_FWCUTTER_SOURCE_URL:=http://download.berlios.de/bcm43xx/
-PKG_FWCUTTER_MD5SUM:=3f7fbf4f8dcd296c6d1b0d42eab0f9ac
+PKG_FWCUTTER_SOURCE_URL:=http://bu3sch.de/b43/fwcutter/
+PKG_FWCUTTER_MD5SUM:=3db2f4de85a459451f5b391cf67a8d44
 
 define KernelPackage/b43
   SUBMENU:=Wireless Drivers
@@ -43,7 +43,6 @@ endef
 
 EXTRA_KCONFIG:= \
        CONFIG_B43=m \
-       CONFIG_B43_DMA=y \
        $(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \
 
 
@@ -73,6 +72,8 @@ define Build/Prepare
        $(CP) ./src/* $(PKG_BUILD_DIR)/
        tar xjf "$(DL_DIR)/$(PKG_FWV4_SOURCE)" -C "$(PKG_BUILD_DIR)"
        tar xjf "$(DL_DIR)/$(PKG_FWCUTTER_SOURCE)" -C "$(PKG_BUILD_DIR)"
+       $(Build/Patch)
+       $(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
 endef
 
 define Build/Configure
index e3c573e56b6368b72cf25751df30016b1ece3a6b..1a2141dabdc7a533cb9382773b674ddbe7a270bd 100644 (file)
@@ -61,16 +61,28 @@ config B43_PCMCIA
 
          If unsure, say N.
 
-# LED support
+config B43_NPHY
+       bool "Pre IEEE 802.11n support (BROKEN)"
+       depends on B43 && EXPERIMENTAL && BROKEN
+       ---help---
+         Support for the IEEE 802.11n draft.
+
+         THIS IS BROKEN AND DOES NOT WORK YET.
+
+         SAY N.
+
+# This config option automatically enables b43 LEDS support,
+# if it's possible.
 config B43_LEDS
        bool
-       depends on B43 && MAC80211_LEDS
+       depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
        default y
 
-# RFKILL support
+# This config option automatically enables b43 RFKILL support,
+# if it's possible.
 config B43_RFKILL
        bool
-       depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
+       depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
        default y
 
 config B43_DEBUG
@@ -81,51 +93,3 @@ config B43_DEBUG
 
          Say Y, if you want to find out why the driver does not
          work for you.
-
-config B43_DMA
-       bool
-       depends on B43
-config B43_PIO
-       bool
-       depends on B43
-
-choice
-       prompt "Broadcom 43xx data transfer mode"
-       depends on B43
-       default B43_DMA_AND_PIO_MODE
-
-config B43_DMA_AND_PIO_MODE
-       bool "DMA + PIO"
-       select B43_DMA
-       select B43_PIO
-       ---help---
-         Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
-         data transfer modes.
-         The actually used mode is selectable through the module
-         parameter "pio". If the module parameter is pio=0, DMA is used.
-         Otherwise PIO is used. DMA is default.
-
-         If unsure, choose this option.
-
-config B43_DMA_MODE
-       bool "DMA (Direct Memory Access) only"
-       select B43_DMA
-       ---help---
-         Only include Direct Memory Access (DMA).
-         This reduces the size of the driver module, by omitting the PIO code.
-
-config B43_PIO_MODE
-       bool "PIO (Programmed I/O) only"
-       select B43_PIO
-       ---help---
-         Only include Programmed I/O (PIO).
-         This reduces the size of the driver module, by omitting the DMA code.
-         Please note that PIO transfers are slow (compared to DMA).
-
-         Also note that not all devices of the 43xx series support PIO.
-         The 4306 (Apple Airport Extreme and others) supports PIO, while
-         the 4318 is known to _not_ support PIO.
-
-         Only use PIO, if DMA does not work for you.
-
-endchoice
index 485e59e2dfabc2c5104fbb61f7cddd19481b743b..ac1329dba04581317c306791c1b5b465dd0a2dba 100644 (file)
@@ -1,20 +1,16 @@
-# b43 core
 b43-y                          += main.o
 b43-y                          += tables.o
+b43-y                          += tables_nphy.o
 b43-y                          += phy.o
+b43-y                          += nphy.o
 b43-y                          += sysfs.o
 b43-y                          += xmit.o
 b43-y                          += lo.o
-# b43 RFKILL button support
+b43-y                          += wa.o
+b43-y                          += dma.o
 b43-$(CONFIG_B43_RFKILL)       += rfkill.o
-# b43 LED support
 b43-$(CONFIG_B43_LEDS)         += leds.o
-# b43 PCMCIA support
 b43-$(CONFIG_B43_PCMCIA)       += pcmcia.o
-# b43 debugging
 b43-$(CONFIG_B43_DEBUG)                += debugfs.o
-# b43 DMA and PIO
-b43-$(CONFIG_B43_DMA)          += dma.o
-b43-$(CONFIG_B43_PIO)          += pio.o
 
 obj-$(CONFIG_B43)              += b43.o
index a28ad230d63e884fee652d2fe420f3137f18e2c7..0dc1aaf46bd57a97619b2e0218aece2a11fc27b4 100644 (file)
@@ -35,8 +35,8 @@
 #define B43_MMIO_DMA4_IRQ_MASK         0x44
 #define B43_MMIO_DMA5_REASON           0x48
 #define B43_MMIO_DMA5_IRQ_MASK         0x4C
-#define B43_MMIO_MACCTL                        0x120
-#define B43_MMIO_STATUS2_BITFIELD      0x124
+#define B43_MMIO_MACCTL                        0x120   /* MAC control */
+#define B43_MMIO_MACCMD                        0x124   /* MAC command */
 #define B43_MMIO_GEN_IRQ_REASON                0x128
 #define B43_MMIO_GEN_IRQ_MASK          0x12C
 #define B43_MMIO_RAM_CONTROL           0x130
@@ -50,6 +50,9 @@
 #define B43_MMIO_XMITSTAT_1            0x174
 #define B43_MMIO_REV3PLUS_TSF_LOW      0x180   /* core rev >= 3 only */
 #define B43_MMIO_REV3PLUS_TSF_HIGH     0x184   /* core rev >= 3 only */
+#define B43_MMIO_TSF_CFP_REP           0x188
+#define B43_MMIO_TSF_CFP_START         0x18C
+#define B43_MMIO_TSF_CFP_MAXDUR                0x190
 
 /* 32-bit DMA */
 #define B43_MMIO_DMA32_BASE0           0x200
 #define B43_MMIO_DMA64_BASE3           0x2C0
 #define B43_MMIO_DMA64_BASE4           0x300
 #define B43_MMIO_DMA64_BASE5           0x340
-/* PIO */
-#define B43_MMIO_PIO1_BASE             0x300
-#define B43_MMIO_PIO2_BASE             0x310
-#define B43_MMIO_PIO3_BASE             0x320
-#define B43_MMIO_PIO4_BASE             0x330
 
 #define B43_MMIO_PHY_VER               0x3E0
 #define B43_MMIO_PHY_RADIO             0x3E2
@@ -88,6 +86,8 @@
 #define B43_MMIO_RADIO_HWENABLED_LO    0x49A
 #define B43_MMIO_GPIO_CONTROL          0x49C
 #define B43_MMIO_GPIO_MASK             0x49E
+#define B43_MMIO_TSF_CFP_START_LOW     0x604
+#define B43_MMIO_TSF_CFP_START_HIGH    0x606
 #define B43_MMIO_TSF_0                 0x632   /* core rev < 3 only */
 #define B43_MMIO_TSF_1                 0x634   /* core rev < 3 only */
 #define B43_MMIO_TSF_2                 0x636   /* core rev < 3 only */
@@ -170,14 +170,17 @@ enum {
 #define B43_SHM_SH_SLOTT               0x0010  /* Slot time */
 #define B43_SHM_SH_DTIMPER             0x0012  /* DTIM period */
 #define B43_SHM_SH_NOSLPZNATDTIM       0x004C  /* NOSLPZNAT DTIM */
-/* SHM_SHARED beacon variables */
+/* SHM_SHARED beacon/AP variables */
 #define B43_SHM_SH_BTL0                        0x0018  /* Beacon template length 0 */
 #define B43_SHM_SH_BTL1                        0x001A  /* Beacon template length 1 */
 #define B43_SHM_SH_BTSFOFF             0x001C  /* Beacon TSF offset */
 #define B43_SHM_SH_TIMBPOS             0x001E  /* TIM B position in beacon */
+#define B43_SHM_SH_DTIMP               0x0012  /* DTIP period */
+#define B43_SHM_SH_MCASTCOOKIE         0x00A8  /* Last bcast/mcast frame ID */
 #define B43_SHM_SH_SFFBLIM             0x0044  /* Short frame fallback retry limit */
 #define B43_SHM_SH_LFFBLIM             0x0046  /* Long frame fallback retry limit */
 #define B43_SHM_SH_BEACPHYCTL          0x0054  /* Beacon PHY TX control word (see PHY TX control) */
+#define B43_SHM_SH_EXTNPHYCTL          0x00B0  /* Extended bytes for beacon PHY control (N) */
 /* SHM_SHARED ACK/CTS control */
 #define B43_SHM_SH_ACKCTSPHYCTL                0x0022  /* ACK/CTS PHY control word (see PHY TX control) */
 /* SHM_SHARED probe response variables */
@@ -273,6 +276,8 @@ enum {
 #define B43_PHYTYPE_A                  0x00
 #define B43_PHYTYPE_B                  0x01
 #define B43_PHYTYPE_G                  0x02
+#define B43_PHYTYPE_N                  0x04
+#define B43_PHYTYPE_LP                 0x05
 
 /* PHYRegisters */
 #define B43_PHY_ILT_A_CTRL             0x0072
@@ -319,17 +324,29 @@ enum {
 #define B43_MACCTL_DISCPMQ             0x40000000      /* Discard Power Management Queue */
 #define B43_MACCTL_GMODE               0x80000000      /* G Mode */
 
-/* 802.11 core specific TM State Low flags */
+/* MAC Command bitfield */
+#define B43_MACCMD_BEACON0_VALID       0x00000001      /* Beacon 0 in template RAM is busy/valid */
+#define B43_MACCMD_BEACON1_VALID       0x00000002      /* Beacon 1 in template RAM is busy/valid */
+#define B43_MACCMD_DFQ_VALID           0x00000004      /* Directed frame queue valid (IBSS PS mode, ATIM) */
+#define B43_MACCMD_CCA                 0x00000008      /* Clear channel assessment */
+#define B43_MACCMD_BGNOISE             0x00000010      /* Background noise */
+
+/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
 #define B43_TMSLOW_GMODE               0x20000000      /* G Mode Enable */
-#define B43_TMSLOW_PLLREFSEL           0x00200000      /* PLL Frequency Reference Select */
+#define B43_TMSLOW_PHYCLKSPEED         0x00C00000      /* PHY clock speed mask (N-PHY only) */
+#define  B43_TMSLOW_PHYCLKSPEED_40MHZ  0x00000000      /* 40 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_80MHZ  0x00400000      /* 80 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_160MHZ 0x00800000      /* 160 MHz PHY */
+#define B43_TMSLOW_PLLREFSEL           0x00200000      /* PLL Frequency Reference Select (rev >= 5) */
 #define B43_TMSLOW_MACPHYCLKEN         0x00100000      /* MAC PHY Clock Control Enable (rev >= 5) */
 #define B43_TMSLOW_PHYRESET            0x00080000      /* PHY Reset */
 #define B43_TMSLOW_PHYCLKEN            0x00040000      /* PHY Clock Enable */
 
-/* 802.11 core specific TM State High flags */
+/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */
+#define B43_TMSHIGH_DUALBAND_PHY       0x00080000      /* Dualband PHY available */
 #define B43_TMSHIGH_FCLOCK             0x00040000      /* Fast Clock Available (rev >= 5) */
-#define B43_TMSHIGH_APHY               0x00020000      /* A-PHY available (rev >= 5) */
-#define B43_TMSHIGH_GPHY               0x00010000      /* G-PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_5GHZ_PHY      0x00020000      /* 5 GHz PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_2GHZ_PHY      0x00010000      /* 2.4 GHz PHY available (rev >= 5) */
 
 /* Generic-Interrupt reasons. */
 #define B43_IRQ_MAC_SUSPENDED          0x00000001
@@ -391,6 +408,8 @@ enum {
 #define B43_DEFAULT_SHORT_RETRY_LIMIT  7
 #define B43_DEFAULT_LONG_RETRY_LIMIT   4
 
+#define B43_PHY_TX_BADNESS_LIMIT       1000
+
 /* Max size of a security key */
 #define B43_SEC_KEYSIZE                        16
 /* Security algorithms. */
@@ -443,10 +462,6 @@ struct b43_phy {
        u8 possible_phymodes;
        /* GMODE bit enabled? */
        bool gmode;
-       /* Possible ieee80211 subsystem hwmodes for this PHY.
-        * Which mode is selected, depends on thr GMODE enabled bit */
-#define B43_MAX_PHYHWMODES     2
-       struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
 
        /* Analog Type */
        u8 analog;
@@ -460,7 +475,6 @@ struct b43_phy {
        u16 radio_ver;          /* Radio version */
        u8 radio_rev;           /* Radio revision */
 
-       bool locked;            /* Only used in b43_phy_{un}lock() */
        bool dyn_tssi_tbl;      /* tssi2dbm is kmalloc()ed. */
 
        /* ACI (adjacent channel interference) flags. */
@@ -497,11 +511,6 @@ struct b43_phy {
        s16 lna_gain;           /* LNA */
        s16 pga_gain;           /* PGA */
 
-       /* PHY lock for core.rev < 3
-        * This lock is only used by b43_phy_{un}lock()
-        */
-       spinlock_t lock;
-
        /* Desired TX power level (in dBm).
         * This is set by the user and adjusted in b43_phy_xmitpower(). */
        u8 power_level;
@@ -512,9 +521,7 @@ struct b43_phy {
        struct b43_bbatt bbatt;
        struct b43_rfatt rfatt;
        u8 tx_control;          /* B43_TXCTL_XXX */
-#ifdef CONFIG_B43_DEBUG
-       bool manual_txpower_control;    /* Manual TX-power control enabled? */
-#endif
+
        /* Hardware Power Control enabled? */
        bool hardware_power_control;
 
@@ -542,6 +549,26 @@ struct b43_phy {
        u16 lofcal;
 
        u16 initval;            //FIXME rename?
+
+       /* PHY TX errors counter. */
+       atomic_t txerr_cnt;
+
+       /* The device does address auto increment for the OFDM tables.
+        * We cache the previously used address here and omit the address
+        * write on the next table access, if possible. */
+       u16 ofdmtab_addr; /* The address currently set in hardware. */
+       enum { /* The last data flow direction. */
+               B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
+               B43_OFDMTAB_DIRECTION_READ,
+               B43_OFDMTAB_DIRECTION_WRITE,
+       } ofdmtab_addr_direction;
+
+#if B43_DEBUG
+       /* Manual TX-power control enabled? */
+       bool manual_txpower_control;
+       /* PHY registers locked by b43_phy_lock()? */
+       bool phy_locked;
+#endif /* B43_DEBUG */
 };
 
 /* Data structures for DMA transmission, per 80211 core. */
@@ -557,14 +584,6 @@ struct b43_dma {
        struct b43_dmaring *rx_ring3;   /* only available on core.rev < 5 */
 };
 
-/* Data structures for PIO transmission, per 80211 core. */
-struct b43_pio {
-       struct b43_pioqueue *queue0;
-       struct b43_pioqueue *queue1;
-       struct b43_pioqueue *queue2;
-       struct b43_pioqueue *queue3;
-};
-
 /* Context information for a noise calculation (Link Quality). */
 struct b43_noise_calculation {
        u8 channel_at_start;
@@ -597,18 +616,18 @@ struct b43_wl {
        /* Pointer to the ieee80211 hardware data structure */
        struct ieee80211_hw *hw;
 
-       spinlock_t irq_lock;
        struct mutex mutex;
+       spinlock_t irq_lock;
+       /* Lock for LEDs access. */
        spinlock_t leds_lock;
+       /* Lock for SHM access. */
+       spinlock_t shm_lock;
 
        /* We can only have one operating interface (802.11 core)
         * at a time. General information about this interface follows.
         */
 
-       /* Opaque ID of the operating interface from the ieee80211
-        * subsystem. Do not modify.
-        */
-       int if_id;
+       struct ieee80211_vif *vif;
        /* The MAC address of the operating interface. */
        u8 mac_addr[ETH_ALEN];
        /* Current BSSID */
@@ -632,18 +651,33 @@ struct b43_wl {
        /* List of all wireless devices on this chip */
        struct list_head devlist;
        u8 nr_devs;
+
+       bool radiotap_enabled;
+
+       /* The beacon we are currently using (AP or IBSS mode).
+        * This beacon stuff is protected by the irq_lock. */
+       struct sk_buff *current_beacon;
+       bool beacon0_uploaded;
+       bool beacon1_uploaded;
+};
+
+/* In-memory representation of a cached microcode file. */
+struct b43_firmware_file {
+       const char *filename;
+       const struct firmware *data;
 };
 
 /* Pointers to the firmware data and meta information about it. */
 struct b43_firmware {
        /* Microcode */
-       const struct firmware *ucode;
+       struct b43_firmware_file ucode;
        /* PCM code */
-       const struct firmware *pcm;
+       struct b43_firmware_file pcm;
        /* Initial MMIO values for the firmware */
-       const struct firmware *initvals;
+       struct b43_firmware_file initvals;
        /* Initial MMIO values for the firmware, band-specific */
-       const struct firmware *initvals_band;
+       struct b43_firmware_file initvals_band;
+
        /* Firmware revision */
        u16 rev;
        /* Firmware patchlevel */
@@ -681,21 +715,16 @@ struct b43_wldev {
        /* Saved init status for handling suspend. */
        int suspend_init_status;
 
-       bool __using_pio;       /* Internal, use b43_using_pio(). */
        bool bad_frames_preempt;        /* Use "Bad Frames Preemption" (default off) */
-       bool reg124_set_0x4;    /* Some variable to keep track of IRQ stuff. */
-       bool short_preamble;    /* TRUE, if short preamble is enabled. */
+       bool dfq_valid;         /* Directed frame queue valid (IBSS PS mode, ATIM) */
        bool short_slot;        /* TRUE, if short slot timing is enabled. */
        bool radio_hw_enable;   /* saved state of radio hardware enabled state */
 
        /* PHY/Radio device. */
        struct b43_phy phy;
-       union {
-               /* DMA engines. */
-               struct b43_dma dma;
-               /* PIO engines. */
-               struct b43_pio pio;
-       };
+
+       /* DMA engines. */
+       struct b43_dma dma;
 
        /* Various statistics about the physical device. */
        struct b43_stats stats;
@@ -730,9 +759,6 @@ struct b43_wldev {
        u8 max_nr_keys;
        struct b43_key key[58];
 
-       /* Cached beacon template while uploading the template. */
-       struct sk_buff *cached_beacon;
-
        /* Firmware data */
        struct b43_firmware fw;
 
@@ -750,28 +776,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
        return hw->priv;
 }
 
-/* Helper function, which returns a boolean.
- * TRUE, if PIO is used; FALSE, if DMA is used.
- */
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-       return dev->__using_pio;
-}
-#elif defined(CONFIG_B43_DMA)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-       return 0;
-}
-#elif defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-       return 1;
-}
-#else
-# error "Using neither DMA nor PIO? Confused..."
-#endif
-
 static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
 {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
index 734e70e1a06d557411b0273d24cf3399d1c6f6be..e38ed0fe72e9c3978bdf1499d6c299c07e84854d 100644 (file)
@@ -34,7 +34,6 @@
 #include "main.h"
 #include "debugfs.h"
 #include "dma.h"
-#include "pio.h"
 #include "xmit.h"
 
 
@@ -128,7 +127,7 @@ static ssize_t shm_read_file(struct b43_wldev *dev,
        __le16 *le16buf = (__le16 *)buf;
 
        for (i = 0; i < 0x1000; i++) {
-               if (bufsize <= 0)
+               if (bufsize < sizeof(tmp))
                        break;
                tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
                le16buf[i] = cpu_to_le16(tmp);
@@ -223,8 +222,6 @@ out:
 static int txpower_g_write_file(struct b43_wldev *dev,
                                const char *buf, size_t count)
 {
-       unsigned long phy_flags;
-
        if (dev->phy.type != B43_PHYTYPE_G)
                return -ENODEV;
        if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
@@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev,
                        dev->phy.tx_control |= B43_TXCTL_PA2DB;
                if (pa3db)
                        dev->phy.tx_control |= B43_TXCTL_PA3DB;
-               b43_phy_lock(dev, phy_flags);
+               b43_phy_lock(dev);
                b43_radio_lock(dev);
                b43_set_txpower_g(dev, &dev->phy.bbatt,
                                  &dev->phy.rfatt, dev->phy.tx_control);
                b43_radio_unlock(dev);
-               b43_phy_unlock(dev, phy_flags);
+               b43_phy_unlock(dev);
        }
 
        return 0;
@@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
        struct b43_wldev *dev;
        struct b43_debugfs_fops *dfops;
        struct b43_dfs_file *dfile;
-       ssize_t ret;
+       ssize_t uninitialized_var(ret);
        char *buf;
        const size_t bufsize = 1024 * 128;
        const size_t buforder = get_order(bufsize);
index 5e8f8ac0f1dda1f2b38f26f13145fef370a95b00..3dfb28a34be9f8259c75bf5490a703cd88303a02 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
 
 /* 32bit DMA ops. */
 static
@@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
        addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
        addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
-       addrhi |= ssb_dma_translation(ring->dev->dev);
+       addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
        if (slot == ring->nr_slots - 1)
                ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
        if (start)
@@ -315,29 +317,27 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
        case 3:
                ring = dev->dma.tx_ring0;
                break;
-       case 4:
-               ring = dev->dma.tx_ring4;
-               break;
-       case 5:
-               ring = dev->dma.tx_ring5;
-               break;
        }
 
        return ring;
 }
 
-/* Bcm43xx-ring to mac80211-queue mapping */
+/* b43-ring to mac80211-queue mapping */
 static inline int txring_to_priority(struct b43_dmaring *ring)
 {
-       static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+       static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
+       unsigned int index;
 
 /*FIXME: have only one queue, for now */
        return 0;
 
-       return idx_to_prio[ring->index];
+       index = ring->index;
+       if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
+               index = 0;
+       return idx_to_prio[index];
 }
 
-u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
 {
        static const u16 map64[] = {
                B43_MMIO_DMA64_BASE0,
@@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
                B43_MMIO_DMA32_BASE5,
        };
 
-       if (dma64bit) {
+       if (type == B43_DMA_64BIT) {
                B43_WARN_ON(!(controller_idx >= 0 &&
                              controller_idx < ARRAY_SIZE(map64)));
                return map64[controller_idx];
@@ -426,9 +426,21 @@ static inline
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
        struct device *dev = ring->dev->dev->dev;
-
+       gfp_t flags = GFP_KERNEL;
+
+       /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
+        * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
+        * has shown that 4K is sufficient for the latter as long as the buffer
+        * does not cross an 8K boundary.
+        *
+        * For unknown reasons - possibly a hardware error - the BCM4311 rev
+        * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
+        * which accounts for the GFP_DMA flag below.
+        */
+       if (ring->type == B43_DMA_64BIT)
+               flags |= GFP_DMA;
        ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
-                                           &(ring->dmabase), GFP_KERNEL);
+                                           &(ring->dmabase), flags);
        if (!ring->descbase) {
                b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
                return -ENOMEM;
@@ -447,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
 }
 
 /* Reset the RX DMA channel */
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -455,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 
        might_sleep();
 
-       offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
+                                                  B43_DMA32_RXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_RXSTAT;
                        if (value == B43_DMA64_RXSTAT_DISABLED) {
                                i = -1;
@@ -483,8 +497,9 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        return 0;
 }
 
-/* Reset the RX DMA channel */
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+/* Reset the TX DMA channel */
+static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -493,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        might_sleep();
 
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED ||
                            value == B43_DMA64_TXSTAT_IDLEWAIT ||
@@ -510,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
                }
                msleep(1);
        }
-       offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED) {
                                i = -1;
@@ -540,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        return 0;
 }
 
+/* Check if a DMA mapping address is invalid. */
+static bool b43_dma_mapping_error(struct b43_dmaring *ring,
+                                 dma_addr_t addr,
+                                 size_t buffersize)
+{
+       if (unlikely(dma_mapping_error(addr)))
+               return 1;
+
+       switch (ring->type) {
+       case B43_DMA_30BIT:
+               if ((u64)addr + buffersize > (1ULL << 30))
+                       return 1;
+               break;
+       case B43_DMA_32BIT:
+               if ((u64)addr + buffersize > (1ULL << 32))
+                       return 1;
+               break;
+       case B43_DMA_64BIT:
+               /* Currently we can't have addresses beyond
+                * 64bit in the kernel. */
+               break;
+       }
+
+       /* The address is OK. */
+       return 0;
+}
+
 static int setup_rx_descbuffer(struct b43_dmaring *ring,
                               struct b43_dmadesc_generic *desc,
                               struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@@ -555,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        if (unlikely(!skb))
                return -ENOMEM;
        dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                /* ugh. try to realloc in zone_dma */
                gfp_flags |= GFP_DMA;
 
@@ -568,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
                                         ring->rx_buffersize, 0);
        }
 
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                dev_kfree_skb_any(skb);
                return -EIO;
        }
@@ -633,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
        u32 trans = ssb_dma_translation(ring->dev->dev);
 
        if (ring->tx) {
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -647,7 +691,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                        b43_dma_write(ring, B43_DMA64_TXRINGHI,
                                      ((ringbase >> 32) &
                                       ~SSB_DMA_TRANSLATION_MASK)
-                                     | trans);
+                                     | (trans << 1));
                } else {
                        u32 ringbase = (u32) (ring->dmabase);
 
@@ -665,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                err = alloc_initial_descbuffers(ring);
                if (err)
                        goto out;
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -680,8 +724,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                        b43_dma_write(ring, B43_DMA64_RXRINGHI,
                                      ((ringbase >> 32) &
                                       ~SSB_DMA_TRANSLATION_MASK)
-                                     | trans);
-                       b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+                                     | (trans << 1));
+                       b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
+                                     sizeof(struct b43_dmadesc64));
                } else {
                        u32 ringbase = (u32) (ring->dmabase);
 
@@ -695,11 +740,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                        b43_dma_write(ring, B43_DMA32_RXRING,
                                      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
                                      | trans);
-                       b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+                       b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
+                                     sizeof(struct b43_dmadesc32));
                }
        }
 
-      out:
+out:
        return err;
 }
 
@@ -708,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
 {
        if (ring->tx) {
                b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
                } else
                        b43_dma_write(ring, B43_DMA32_TXRING, 0);
        } else {
                b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
                } else
@@ -772,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
 static
 struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                      int controller_index,
-                                     int for_tx, int dma64)
+                                     int for_tx,
+                                     enum b43_dmatype type)
 {
        struct b43_dmaring *ring;
        int err;
@@ -782,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
        if (!ring)
                goto out;
+       ring->type = type;
 
        nr_slots = B43_RXRING_SLOTS;
        if (for_tx)
@@ -793,7 +841,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                goto err_kfree_ring;
        if (for_tx) {
                ring->txhdr_cache = kcalloc(nr_slots,
-                                           sizeof(struct b43_txhdr_fw4),
+                                           b43_txhdr_size(dev),
                                            GFP_KERNEL);
                if (!ring->txhdr_cache)
                        goto err_kfree_meta;
@@ -801,39 +849,38 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                /* test for ability to dma to txhdr_cache */
                dma_test = dma_map_single(dev->dev->dev,
                                          ring->txhdr_cache,
-                                         sizeof(struct b43_txhdr_fw4),
+                                         b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
 
-               if (dma_mapping_error(dma_test)) {
+               if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
                        /* ugh realloc */
                        kfree(ring->txhdr_cache);
                        ring->txhdr_cache = kcalloc(nr_slots,
-                                                   sizeof(struct
-                                                          b43_txhdr_fw4),
+                                                   b43_txhdr_size(dev),
                                                    GFP_KERNEL | GFP_DMA);
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
                        dma_test = dma_map_single(dev->dev->dev,
                                                  ring->txhdr_cache,
-                                                 sizeof(struct b43_txhdr_fw4),
+                                                 b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
 
-                       if (dma_mapping_error(dma_test))
+                       if (b43_dma_mapping_error(ring, dma_test,
+                                                 b43_txhdr_size(dev)))
                                goto err_kfree_txhdr_cache;
                }
 
                dma_unmap_single(dev->dev->dev,
-                                dma_test, sizeof(struct b43_txhdr_fw4),
+                                dma_test, b43_txhdr_size(dev),
                                 DMA_TO_DEVICE);
        }
 
        ring->dev = dev;
        ring->nr_slots = nr_slots;
-       ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+       ring->mmio_base = b43_dmacontroller_base(type, controller_index);
        ring->index = controller_index;
-       ring->dma64 = !!dma64;
-       if (dma64)
+       if (type == B43_DMA_64BIT)
                ring->ops = &dma64_ops;
        else
                ring->ops = &dma32_ops;
@@ -883,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
        if (!ring)
                return;
 
-       b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
-              (ring->dma64) ? "64" : "32",
+       b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+              (unsigned int)(ring->type),
               ring->mmio_base,
               (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
        /* Device IRQs are disabled prior entering this function,
@@ -901,11 +948,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
 
 void b43_dma_free(struct b43_wldev *dev)
 {
-       struct b43_dma *dma;
-
-       if (b43_using_pio(dev))
-               return;
-       dma = &dev->dma;
+       struct b43_dma *dma = &dev->dma;
 
        b43_destroy_dmaring(dma->rx_ring3);
        dma->rx_ring3 = NULL;
@@ -932,74 +975,78 @@ int b43_dma_init(struct b43_wldev *dev)
        struct b43_dmaring *ring;
        int err;
        u64 dmamask;
-       int dma64 = 0;
+       enum b43_dmatype type;
 
        dmamask = supported_dma_mask(dev);
-       if (dmamask == DMA_64BIT_MASK)
-               dma64 = 1;
-
+       switch (dmamask) {
+       default:
+               B43_WARN_ON(1);
+       case DMA_30BIT_MASK:
+               type = B43_DMA_30BIT;
+               break;
+       case DMA_32BIT_MASK:
+               type = B43_DMA_32BIT;
+               break;
+       case DMA_64BIT_MASK:
+               type = B43_DMA_64BIT;
+               break;
+       }
        err = ssb_dma_set_mask(dev->dev, dmamask);
        if (err) {
-#ifdef B43_PIO
-               b43warn(dev->wl, "DMA for this device not supported. "
-                       "Falling back to PIO\n");
-               dev->__using_pio = 1;
-               return -EAGAIN;
-#else
-               b43err(dev->wl, "DMA for this device not supported and "
-                      "no PIO support compiled in\n");
+               b43err(dev->wl, "The machine/kernel does not support "
+                      "the required DMA mask (0x%08X%08X)\n",
+                      (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
+                      (unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
                return -EOPNOTSUPP;
-#endif
        }
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 1, dma64);
+       ring = b43_setup_dmaring(dev, 0, 1, type);
        if (!ring)
                goto out;
        dma->tx_ring0 = ring;
 
-       ring = b43_setup_dmaring(dev, 1, 1, dma64);
+       ring = b43_setup_dmaring(dev, 1, 1, type);
        if (!ring)
                goto err_destroy_tx0;
        dma->tx_ring1 = ring;
 
-       ring = b43_setup_dmaring(dev, 2, 1, dma64);
+       ring = b43_setup_dmaring(dev, 2, 1, type);
        if (!ring)
                goto err_destroy_tx1;
        dma->tx_ring2 = ring;
 
-       ring = b43_setup_dmaring(dev, 3, 1, dma64);
+       ring = b43_setup_dmaring(dev, 3, 1, type);
        if (!ring)
                goto err_destroy_tx2;
        dma->tx_ring3 = ring;
 
-       ring = b43_setup_dmaring(dev, 4, 1, dma64);
+       ring = b43_setup_dmaring(dev, 4, 1, type);
        if (!ring)
                goto err_destroy_tx3;
        dma->tx_ring4 = ring;
 
-       ring = b43_setup_dmaring(dev, 5, 1, dma64);
+       ring = b43_setup_dmaring(dev, 5, 1, type);
        if (!ring)
                goto err_destroy_tx4;
        dma->tx_ring5 = ring;
 
        /* setup RX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 0, dma64);
+       ring = b43_setup_dmaring(dev, 0, 0, type);
        if (!ring)
                goto err_destroy_tx5;
        dma->rx_ring0 = ring;
 
        if (dev->dev->id.revision < 5) {
-               ring = b43_setup_dmaring(dev, 3, 0, dma64);
+               ring = b43_setup_dmaring(dev, 3, 0, type);
                if (!ring)
                        goto err_destroy_rx0;
                dma->rx_ring3 = ring;
        }
 
-       b43dbg(dev->wl, "%d-bit DMA initialized\n",
-              (dmamask == DMA_64BIT_MASK) ? 64 :
-              (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+       b43dbg(dev->wl, "%u-bit DMA initialized\n",
+              (unsigned int)type);
        err = 0;
       out:
        return err;
@@ -1038,26 +1085,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
         * in the lower 12 bits.
         * Note that the cookie must never be 0, as this
         * is a special value used in RX path.
+        * It can also not be 0xFFFF because that is special
+        * for multicast frames.
         */
        switch (ring->index) {
        case 0:
-               cookie = 0xA000;
+               cookie = 0x1000;
                break;
        case 1:
-               cookie = 0xB000;
+               cookie = 0x2000;
                break;
        case 2:
-               cookie = 0xC000;
+               cookie = 0x3000;
                break;
        case 3:
-               cookie = 0xD000;
+               cookie = 0x4000;
                break;
        case 4:
-               cookie = 0xE000;
+               cookie = 0x5000;
                break;
        case 5:
-               cookie = 0xF000;
+               cookie = 0x6000;
                break;
+       default:
+               B43_WARN_ON(1);
        }
        B43_WARN_ON(slot & ~0x0FFF);
        cookie |= (u16) slot;
@@ -1073,22 +1124,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
        struct b43_dmaring *ring = NULL;
 
        switch (cookie & 0xF000) {
-       case 0xA000:
+       case 0x1000:
                ring = dma->tx_ring0;
                break;
-       case 0xB000:
+       case 0x2000:
                ring = dma->tx_ring1;
                break;
-       case 0xC000:
+       case 0x3000:
                ring = dma->tx_ring2;
                break;
-       case 0xD000:
+       case 0x4000:
                ring = dma->tx_ring3;
                break;
-       case 0xE000:
+       case 0x5000:
                ring = dma->tx_ring4;
                break;
-       case 0xF000:
+       case 0x6000:
                ring = dma->tx_ring5;
                break;
        default:
@@ -1106,32 +1157,45 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 {
        const struct b43_dma_ops *ops = ring->ops;
        u8 *header;
-       int slot;
+       int slot, old_top_slot, old_used_slots;
        int err;
        struct b43_dmadesc_generic *desc;
        struct b43_dmadesc_meta *meta;
        struct b43_dmadesc_meta *meta_hdr;
        struct sk_buff *bounce_skb;
+       u16 cookie;
+       size_t hdrsize = b43_txhdr_size(ring->dev);
 
 #define SLOTS_PER_PACKET  2
        B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 
+       old_top_slot = ring->current_slot;
+       old_used_slots = ring->used_slots;
+
        /* Get a slot for the header. */
        slot = request_slot(ring);
        desc = ops->idx2desc(ring, slot, &meta_hdr);
        memset(meta_hdr, 0, sizeof(*meta_hdr));
 
-       header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
-       b43_generate_txhdr(ring->dev, header,
-                          skb->data, skb->len, ctl,
-                          generate_cookie(ring, slot));
+       header = &(ring->txhdr_cache[slot * hdrsize]);
+       cookie = generate_cookie(ring, slot);
+       err = b43_generate_txhdr(ring->dev, header,
+                                skb->data, skb->len, ctl, cookie);
+       if (unlikely(err)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
+               return err;
+       }
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
-                                          sizeof(struct b43_txhdr_fw4), 1);
-       if (dma_mapping_error(meta_hdr->dmaaddr))
+                                          hdrsize, 1);
+       if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
                return -EIO;
+       }
        ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
-                            sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+                            hdrsize, 1, 0, 0);
 
        /* Get a slot for the payload. */
        slot = request_slot(ring);
@@ -1144,9 +1208,11 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
        /* create a bounce buffer in zone_dma on mapping failure. */
-       if (dma_mapping_error(meta->dmaaddr)) {
+       if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -ENOMEM;
                        goto out_unmap_hdr;
                }
@@ -1156,7 +1222,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
                skb = bounce_skb;
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-               if (dma_mapping_error(meta->dmaaddr)) {
+               if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -EIO;
                        goto out_free_bounce;
                }
@@ -1164,16 +1232,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
 
+       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+               /* Tell the firmware about the cookie of the last
+                * mcast frame, so it can clear the more-data bit in it. */
+               b43_shm_write16(ring->dev, B43_SHM_SHARED,
+                               B43_SHM_SH_MCASTCOOKIE, cookie);
+       }
        /* Now transfer the whole frame. */
        wmb();
        ops->poke_tx(ring, next_slot(ring, slot));
        return 0;
 
-      out_free_bounce:
+out_free_bounce:
        dev_kfree_skb_any(skb);
-      out_unmap_hdr:
+out_unmap_hdr:
        unmap_descbuffer(ring, meta_hdr->dmaaddr,
-                        sizeof(struct b43_txhdr_fw4), 1);
+                        hdrsize, 1);
        return err;
 }
 
@@ -1202,10 +1276,27 @@ int b43_dma_tx(struct b43_wldev *dev,
               struct sk_buff *skb, struct ieee80211_tx_control *ctl)
 {
        struct b43_dmaring *ring;
+       struct ieee80211_hdr *hdr;
        int err = 0;
        unsigned long flags;
 
-       ring = priority_to_txring(dev, ctl->queue);
+       if (unlikely(skb->len < 2 + 2 + 6)) {
+               /* Too short, this can't be a valid frame. */
+               return -EINVAL;
+       }
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+               /* The multicast ring will be sent after the DTIM */
+               ring = dev->dma.tx_ring4;
+               /* Set the more-data bit. Ucode will clear it on
+                * the last frame for us. */
+               hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       } else {
+               /* Decide by priority where to put this frame. */
+               ring = priority_to_txring(dev, ctl->queue);
+       }
+
        spin_lock_irqsave(&ring->lock, flags);
        B43_WARN_ON(!ring->tx);
        if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@@ -1219,6 +1310,13 @@ int b43_dma_tx(struct b43_wldev *dev,
        B43_WARN_ON(ring->stopped);
 
        err = dma_tx_fragment(ring, skb, ctl);
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               dev_kfree_skb_any(skb);
+               err = 0;
+               goto out_unlock;
+       }
        if (unlikely(err)) {
                b43err(dev->wl, "DMA tx mapping failure\n");
                goto out_unlock;
@@ -1233,7 +1331,7 @@ int b43_dma_tx(struct b43_wldev *dev,
                        b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
                }
        }
-      out_unlock:
+out_unlock:
        spin_unlock_irqrestore(&ring->lock, flags);
 
        return err;
@@ -1265,7 +1363,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                                         1);
                else
                        unmap_descbuffer(ring, meta->dmaaddr,
-                                        sizeof(struct b43_txhdr_fw4), 1);
+                                        b43_txhdr_size(dev), 1);
 
                if (meta->is_last_fragment) {
                        B43_WARN_ON(!meta->skb);
index 3eed185be72552194cab5a1f0c6f8f13e21b1a16..c0d6b69e650128fa68dc7825f8cf00c10e23f073 100644 (file)
@@ -170,8 +170,6 @@ struct b43_dmadesc_generic {
 #define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
 #define B43_DMA3_RX_BUFFERSIZE 16
 
-#ifdef CONFIG_B43_DMA
-
 struct sk_buff;
 struct b43_private;
 struct b43_txstatus;
@@ -205,6 +203,12 @@ struct b43_dma_ops {
        void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
 };
 
+enum b43_dmatype {
+       B43_DMA_30BIT   = 30,
+       B43_DMA_32BIT   = 32,
+       B43_DMA_64BIT   = 64,
+};
+
 struct b43_dmaring {
        /* Lowlevel DMA ops. */
        const struct b43_dma_ops *ops;
@@ -237,8 +241,8 @@ struct b43_dmaring {
        int index;
        /* Boolean. Is this a TX ring? */
        bool tx;
-       /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
-       bool dma64;
+       /* The type of DMA engine used. */
+       enum b43_dmatype type;
        /* Boolean. Is this ring stopped at ieee80211 level? */
        bool stopped;
        /* Lock, only used for TX. */
@@ -257,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
        return b43_read32(ring->dev, ring->mmio_base + offset);
 }
 
-static inline
-    void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
 {
        b43_write32(ring->dev, ring->mmio_base + offset, value);
 }
@@ -266,13 +269,6 @@ static inline
 int b43_dma_init(struct b43_wldev *dev);
 void b43_dma_free(struct b43_wldev *dev);
 
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-
-u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
 void b43_dma_tx_suspend(struct b43_wldev *dev);
 void b43_dma_tx_resume(struct b43_wldev *dev);
 
@@ -286,52 +282,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 
 void b43_dma_rx(struct b43_dmaring *ring);
 
-#else /* CONFIG_B43_DMA */
-
-static inline int b43_dma_init(struct b43_wldev *dev)
-{
-       return 0;
-}
-static inline void b43_dma_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-                                  u16 dmacontroller_mmio_base, int dma64)
-{
-       return 0;
-}
-static inline
-    int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-                                  u16 dmacontroller_mmio_base, int dma64)
-{
-       return 0;
-}
-static inline
-    void b43_dma_get_tx_stats(struct b43_wldev *dev,
-                             struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline
-    int b43_dma_tx(struct b43_wldev *dev,
-                  struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-       return 0;
-}
-static inline
-    void b43_dma_handle_txstatus(struct b43_wldev *dev,
-                                const struct b43_txstatus *status)
-{
-}
-static inline void b43_dma_rx(struct b43_dmaring *ring)
-{
-}
-static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_dma_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_DMA */
 #endif /* B43_DMA_H_ */
index 19e588582c7c4d42ed22493afcdca825ca64e9c9..4b590d8c65ff08317fc6405546545e64bc104115 100644 (file)
@@ -4,7 +4,7 @@
   LED control
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -163,6 +163,9 @@ static void b43_map_led(struct b43_wldev *dev,
                b43_register_led(dev, &dev->led_radio, name,
                                 b43_rfkill_led_name(dev),
                                 led_index, activelow);
+               /* Sync the RF-kill LED state with the switch state. */
+               if (dev->radio_hw_enable)
+                       b43_led_turn_on(dev, led_index, activelow);
                break;
        case B43_LED_WEIRD:
        case B43_LED_ASSOC:
@@ -187,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev)
        enum b43_led_behaviour behaviour;
        bool activelow;
 
-       sprom[0] = bus->sprom.r1.gpio0;
-       sprom[1] = bus->sprom.r1.gpio1;
-       sprom[2] = bus->sprom.r1.gpio2;
-       sprom[3] = bus->sprom.r1.gpio3;
+       sprom[0] = bus->sprom.gpio0;
+       sprom[1] = bus->sprom.gpio1;
+       sprom[2] = bus->sprom.gpio2;
+       sprom[3] = bus->sprom.gpio3;
 
        for (i = 0; i < 4; i++) {
                if (sprom[i] == 0xFF) {
@@ -232,4 +235,5 @@ void b43_leds_exit(struct b43_wldev *dev)
        b43_unregister_led(&dev->led_tx);
        b43_unregister_led(&dev->led_rx);
        b43_unregister_led(&dev->led_assoc);
+       b43_unregister_led(&dev->led_radio);
 }
index b14a1753a0d7a7e1f0770d00aef2b3e80bbec26b..d890f366a23b76a021a18807238c54fdf09b9d31 100644 (file)
@@ -5,7 +5,7 @@
   G PHY LO (LocalOscillator) Measuring and Control routines
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
                rfover |= pga;
                rfover |= lna;
                rfover |= trsw_rx;
-               if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
-                   phy->rev > 6)
+               if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+                   && phy->rev > 6)
                        rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
                b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
@@ -555,20 +555,20 @@ struct lo_g_saved_values {
        u16 phy_extg_01;
        u16 phy_dacctl_hwpctl;
        u16 phy_dacctl;
-       u16 phy_base_14;
+       u16 phy_cck_14;
        u16 phy_hpwr_tssictl;
        u16 phy_analogover;
        u16 phy_analogoverval;
        u16 phy_rfover;
        u16 phy_rfoverval;
        u16 phy_classctl;
-       u16 phy_base_3E;
+       u16 phy_cck_3E;
        u16 phy_crs0;
        u16 phy_pgactl;
-       u16 phy_base_2A;
+       u16 phy_cck_2A;
        u16 phy_syncctl;
-       u16 phy_base_30;
-       u16 phy_base_06;
+       u16 phy_cck_30;
+       u16 phy_cck_06;
 
        /* Radio registers */
        u16 radio_43;
@@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
                sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
                sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
                sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
-               sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+               sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
                sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
 
                b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
@@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
                b43_phy_write(dev, B43_PHY_DACCTL,
                              b43_phy_read(dev, B43_PHY_DACCTL)
                              | 0x40);
-               b43_phy_write(dev, B43_PHY_BASE(0x14),
-                             b43_phy_read(dev, B43_PHY_BASE(0x14))
+               b43_phy_write(dev, B43_PHY_CCK(0x14),
+                             b43_phy_read(dev, B43_PHY_CCK(0x14))
                              | 0x200);
        }
        if (phy->type == B43_PHYTYPE_B &&
            phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
-               b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
-               b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+               b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
+               b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
        }
        if (!lo->rebuild && b43_has_hardware_pctl(phy))
                lo_read_power_vector(dev);
@@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
                sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
                sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
                sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
-               sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+               sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
                sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
 
                b43_phy_write(dev, B43_PHY_CLASSCTL,
@@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
                              & 0xFFFC);
                if (phy->type == B43_PHYTYPE_G) {
                        if ((phy->rev >= 7) &&
-                           (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+                           (sprom->boardflags_lo & B43_BFL_EXTLNA)) {
                                b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
                        } else {
                                b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
@@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
                } else {
                        b43_phy_write(dev, B43_PHY_RFOVER, 0);
                }
-               b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+               b43_phy_write(dev, B43_PHY_CCK(0x3E), 0);
        }
        sav->reg_3F4 = b43_read16(dev, 0x3F4);
        sav->reg_3E2 = b43_read16(dev, 0x3E2);
        sav->radio_43 = b43_radio_read16(dev, 0x43);
        sav->radio_7A = b43_radio_read16(dev, 0x7A);
        sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-       sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+       sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A));
        sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
        sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
 
@@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
                sav->radio_52 &= 0x00F0;
        }
        if (phy->type == B43_PHYTYPE_B) {
-               sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
-               sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
-               b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
-               b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+               sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
+               sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06));
+               b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF);
+               b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F);
        } else {
                b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
                            | 0x8000);
@@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
                    & 0xF000);
 
        tmp =
-           (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+           (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E);
        b43_phy_write(dev, tmp, 0x007F);
 
        tmp = sav->phy_syncctl;
@@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev,
        tmp = sav->radio_7A;
        b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+       b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3);
        if (phy->type == B43_PHYTYPE_G ||
            (phy->type == B43_PHYTYPE_B &&
             phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
-               b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+               b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003);
        } else
-               b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+               b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
        if (phy->rev >= 2)
                b43_dummy_transmission(dev);
        b43_radio_selectchannel(dev, 6, 0);
        b43_radio_read16(dev, 0x51);    /* dummy read */
        if (phy->type == B43_PHYTYPE_G)
-               b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+               b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
        if (lo->rebuild)
                lo_measure_txctl_values(dev);
        if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
                b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
        } else {
                if (phy->type == B43_PHYTYPE_B)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
                else
                        b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
        }
@@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev,
        }
        if (phy->type == B43_PHYTYPE_G) {
                if (phy->rev >= 3)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
                else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
                if (phy->rev >= 2)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202);
                else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101);
        }
        b43_write16(dev, 0x3F4, sav->reg_3F4);
        b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
-       b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+       b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A);
        b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
        b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
        b43_radio_write16(dev, 0x43, sav->radio_43);
@@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev,
        b43_write16(dev, 0x3E2, sav->reg_3E2);
        if (phy->type == B43_PHYTYPE_B &&
            phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
-               b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
-               b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+               b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30);
+               b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06);
        }
        if (phy->rev >= 2) {
                b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
@@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
                b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
                b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
                b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
-               b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+               b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
                b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
        }
        if (b43_has_hardware_pctl(phy)) {
@@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
                b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
                b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
                b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
-               b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+               b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
                b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
        }
        b43_radio_selectchannel(dev, sav->old_channel, 1);
index 9f8175c25a8a2785887e930a23613eed10282c30..afb109447a45d4e7341d413a1a381277b781d0c4 100644 (file)
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -46,7 +46,6 @@
 #include "debugfs.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
@@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-extern char *nvram_get(char *name);
-
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static int modparam_pio;
-module_param_named(pio, modparam_pio, int, 0444);
-MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
-#elif defined(CONFIG_B43_DMA)
-# define modparam_pio  0
-#elif defined(CONFIG_B43_PIO)
-# define modparam_pio  1
-#endif
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
 MODULE_PARM_DESC(bad_frames_preempt,
                 "enable(1) / disable(0) Bad Frames Preemption");
 
-static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
-module_param_named(short_retry, modparam_short_retry, int, 0444);
-MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
-
-static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
-module_param_named(long_retry, modparam_long_retry, int, 0444);
-MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
@@ -101,52 +81,41 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
        SSB_DEVTABLE_END
 };
 
 MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
 
-static const struct pci_device_id b43_pci_bridge_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
-
-static struct pci_driver b43_pci_bridge_driver = {
-       .name = "b43-pci-bridge",
-       .id_table = b43_pci_bridge_tbl,
-};
 /* Channel and ratetables are shared for all devices.
  * They can't be const, because ieee80211 puts some precalculated
  * data in there. This data is the same for all devices, so we don't
  * get concurrency issues */
 #define RATETAB_ENT(_rateid, _flags) \
-       {                                                       \
-               .rate   = B43_RATE_TO_BASE100KBPS(_rateid),     \
-               .val    = (_rateid),                            \
-               .val2   = (_rateid),                            \
-               .flags  = (_flags),                             \
+       {                                                               \
+               .bitrate        = B43_RATE_TO_BASE100KBPS(_rateid),     \
+               .hw_value       = (_rateid),                            \
+               .flags          = (_flags),                             \
        }
+
+/*
+ * NOTE: When changing this, sync with xmit.c's
+ *      b43_plcp_get_bitrate_idx_* functions!
+ */
 static struct ieee80211_rate __b43_ratetable[] = {
-       RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
-       RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+       RATETAB_ENT(B43_CCK_RATE_1MB, 0),
+       RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
 };
 
 #define b43_a_ratetable                (__b43_ratetable + 4)
@@ -158,16 +127,10 @@ static struct ieee80211_rate __b43_ratetable[] = {
 
 #define CHANTAB_ENT(_chanid, _freq) \
        {                                                       \
-               .chan   = (_chanid),                            \
-               .freq   = (_freq),                              \
-               .val    = (_chanid),                            \
-               .flag   = IEEE80211_CHAN_W_SCAN |               \
-                         IEEE80211_CHAN_W_ACTIVE_SCAN |        \
-                         IEEE80211_CHAN_W_IBSS,                \
-               .power_level    = 0xFF,                         \
-               .antenna_max    = 0xFF,                         \
+               .center_freq    = (_freq),                      \
+               .hw_value       = (_chanid),                    \
        }
-static struct ieee80211_channel b43_bg_chantable[] = {
+static struct ieee80211_channel b43_2ghz_chantable[] = {
        CHANTAB_ENT(1, 2412),
        CHANTAB_ENT(2, 2417),
        CHANTAB_ENT(3, 2422),
@@ -184,8 +147,8 @@ static struct ieee80211_channel b43_bg_chantable[] = {
        CHANTAB_ENT(14, 2484),
 };
 
-#define b43_bg_chantable_size  ARRAY_SIZE(b43_bg_chantable)
-static struct ieee80211_channel b43_a_chantable[] = {
+#ifdef NOTYET
+static struct ieee80211_channel b43_5ghz_chantable[] = {
        CHANTAB_ENT(36, 5180),
        CHANTAB_ENT(40, 5200),
        CHANTAB_ENT(44, 5220),
@@ -201,7 +164,20 @@ static struct ieee80211_channel b43_a_chantable[] = {
        CHANTAB_ENT(165, 5825),
 };
 
-#define b43_a_chantable_size   ARRAY_SIZE(b43_a_chantable)
+static struct ieee80211_supported_band b43_band_5GHz = {
+       .channels = b43_5ghz_chantable,
+       .n_channels = ARRAY_SIZE(b43_5ghz_chantable),
+       .bitrates = b43_a_ratetable,
+       .n_bitrates = b43_a_ratetable_size,
+};
+#endif
+
+static struct ieee80211_supported_band b43_band_2GHz = {
+       .channels = b43_2ghz_chantable,
+       .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
+       .bitrates = b43_g_ratetable,
+       .n_bitrates = b43_g_ratetable_size,
+};
 
 static void b43_wireless_core_exit(struct b43_wldev *dev);
 static int b43_wireless_core_init(struct b43_wldev *dev);
@@ -286,13 +262,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
        b43_write32(dev, B43_MMIO_RAM_DATA, val);
 }
 
-static inline
-    void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+static inline void b43_shm_control_word(struct b43_wldev *dev,
+                                       u16 routing, u16 offset)
 {
        u32 control;
 
        /* "offset" is the WORD offset. */
-
        control = routing;
        control <<= 16;
        control |= offset;
@@ -301,8 +276,11 @@ static inline
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
        u32 ret;
 
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -313,20 +291,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
                        b43_shm_control_word(dev, routing, (offset >> 2) + 1);
                        ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
 
-                       return ret;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 
        return ret;
 }
 
 u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
        u16 ret;
 
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -334,55 +317,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
                        b43_shm_control_word(dev, routing, offset >> 2);
                        ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
 
-                       return ret;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 
        return ret;
 }
 
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
                        /* Unaligned access */
                        b43_shm_control_word(dev, routing, offset >> 2);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
                                    (value >> 16) & 0xffff);
-                       mmiowb();
                        b43_shm_control_word(dev, routing, (offset >> 2) + 1);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-                       return;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
-       mmiowb();
        b43_write32(dev, B43_MMIO_SHM_DATA, value);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
                        /* Unaligned access */
                        b43_shm_control_word(dev, routing, offset >> 2);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-                       return;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_SHM_DATA, value);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 /* Read HostFlags */
@@ -1029,9 +1020,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
 static void b43_generate_noise_sample(struct b43_wldev *dev)
 {
        b43_jssi_write(dev, 0x7F7F7F7F);
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-                   b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-                   | (1 << 4));
+       b43_write32(dev, B43_MMIO_MACCMD,
+                   b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
        B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
 }
 
@@ -1117,18 +1107,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev)
                if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
                        b43_power_saving_ctl_bits(dev, 0);
        }
-       dev->reg124_set_0x4 = 0;
        if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
-               dev->reg124_set_0x4 = 1;
+               dev->dfq_valid = 1;
 }
 
 static void handle_irq_atim_end(struct b43_wldev *dev)
 {
-       if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
-               return;
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-                   b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-                   | 0x4);
+       if (dev->dfq_valid) {
+               b43_write32(dev, B43_MMIO_MACCMD,
+                           b43_read32(dev, B43_MMIO_MACCMD)
+                           | B43_MACCMD_DFQ_VALID);
+               dev->dfq_valid = 0;
+       }
 }
 
 static void handle_irq_pmq(struct b43_wldev *dev)
@@ -1183,29 +1173,74 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
                                      u16 ram_offset,
                                      u16 shm_size_offset, u8 rate)
 {
-       int len;
-       const u8 *data;
+       unsigned int i, len, variable_len;
+       const struct ieee80211_mgmt *bcn;
+       const u8 *ie;
+       bool tim_found = 0;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       len = min((size_t) dev->cached_beacon->len,
+       bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+       len = min((size_t) dev->wl->current_beacon->len,
                  0x200 - sizeof(struct b43_plcp_hdr6));
-       data = (const u8 *)(dev->cached_beacon->data);
-       b43_write_template_common(dev, data,
+
+       b43_write_template_common(dev, (const u8 *)bcn,
                                  len, ram_offset, shm_size_offset, rate);
+
+       /* Find the position of the TIM and the DTIM_period value
+        * and write them to SHM. */
+       ie = bcn->u.beacon.variable;
+       variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+       for (i = 0; i < variable_len - 2; ) {
+               uint8_t ie_id, ie_len;
+
+               ie_id = ie[i];
+               ie_len = ie[i + 1];
+               if (ie_id == 5) {
+                       u16 tim_position;
+                       u16 dtim_period;
+                       /* This is the TIM Information Element */
+
+                       /* Check whether the ie_len is in the beacon data range. */
+                       if (variable_len < ie_len + 2 + i)
+                               break;
+                       /* A valid TIM is at least 4 bytes long. */
+                       if (ie_len < 4)
+                               break;
+                       tim_found = 1;
+
+                       tim_position = sizeof(struct b43_plcp_hdr6);
+                       tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
+                       tim_position += i;
+
+                       dtim_period = ie[i + 3];
+
+                       b43_shm_write16(dev, B43_SHM_SHARED,
+                                       B43_SHM_SH_TIMBPOS, tim_position);
+                       b43_shm_write16(dev, B43_SHM_SHARED,
+                                       B43_SHM_SH_DTIMPER, dtim_period);
+                       break;
+               }
+               i += ie_len + 2;
+       }
+       if (!tim_found) {
+               b43warn(dev->wl, "Did not find a valid TIM IE in "
+                       "the beacon template packet. AP or IBSS operation "
+                       "may be broken.\n");
+       }
 }
 
 static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
-                                     u16 shm_offset, u16 size, u8 rate)
+                                     u16 shm_offset, u16 size,
+                                     struct ieee80211_rate *rate)
 {
        struct b43_plcp_hdr4 plcp;
        u32 tmp;
        __le16 dur;
 
        plcp.data = 0;
-       b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+       b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
        dur = ieee80211_generic_frame_duration(dev->wl->hw,
-                                              dev->wl->if_id, size,
-                                              B43_RATE_TO_BASE100KBPS(rate));
+                                              dev->wl->vif, size,
+                                              rate);
        /* Write PLCP in two parts and timing for packet transfer */
        tmp = le32_to_cpu(plcp.data);
        b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
@@ -1219,40 +1254,44 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
  * 2) Patching duration field
  * 3) Stripping TIM
  */
-static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
-                                  u16 * dest_size, u8 rate)
+static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
+                                         u16 *dest_size,
+                                         struct ieee80211_rate *rate)
 {
        const u8 *src_data;
        u8 *dest_data;
        u16 src_size, elem_size, src_pos, dest_pos;
        __le16 dur;
        struct ieee80211_hdr *hdr;
+       size_t ie_start;
+
+       src_size = dev->wl->current_beacon->len;
+       src_data = (const u8 *)dev->wl->current_beacon->data;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       src_size = dev->cached_beacon->len;
-       src_data = (const u8 *)dev->cached_beacon->data;
+       /* Get the start offset of the variable IEs in the packet. */
+       ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+       B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
 
-       if (unlikely(src_size < 0x24)) {
-               b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+       if (B43_WARN_ON(src_size < ie_start))
                return NULL;
-       }
 
        dest_data = kmalloc(src_size, GFP_ATOMIC);
        if (unlikely(!dest_data))
                return NULL;
 
-       /* 0x24 is offset of first variable-len Information-Element
-        * in beacon frame.
-        */
-       memcpy(dest_data, src_data, 0x24);
-       src_pos = dest_pos = 0x24;
-       for (; src_pos < src_size - 2; src_pos += elem_size) {
+       /* Copy the static data and all Information Elements, except the TIM. */
+       memcpy(dest_data, src_data, ie_start);
+       src_pos = ie_start;
+       dest_pos = ie_start;
+       for ( ; src_pos < src_size - 2; src_pos += elem_size) {
                elem_size = src_data[src_pos + 1] + 2;
-               if (src_data[src_pos] != 0x05) {        /* TIM */
-                       memcpy(dest_data + dest_pos, src_data + src_pos,
-                              elem_size);
-                       dest_pos += elem_size;
+               if (src_data[src_pos] == 5) {
+                       /* This is the TIM. */
+                       continue;
                }
+               memcpy(dest_data + dest_pos, src_data + src_pos,
+                      elem_size);
+               dest_pos += elem_size;
        }
        *dest_size = dest_pos;
        hdr = (struct ieee80211_hdr *)dest_data;
@@ -1261,8 +1300,8 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
        hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                         IEEE80211_STYPE_PROBE_RESP);
        dur = ieee80211_generic_frame_duration(dev->wl->hw,
-                                              dev->wl->if_id, *dest_size,
-                                              B43_RATE_TO_BASE100KBPS(rate));
+                                              dev->wl->vif, *dest_size,
+                                              rate);
        hdr->duration_id = dur;
 
        return dest_data;
@@ -1270,13 +1309,13 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
 
 static void b43_write_probe_resp_template(struct b43_wldev *dev,
                                          u16 ram_offset,
-                                         u16 shm_size_offset, u8 rate)
+                                         u16 shm_size_offset,
+                                         struct ieee80211_rate *rate)
 {
-       u8 *probe_resp_data;
+       const u8 *probe_resp_data;
        u16 size;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       size = dev->cached_beacon->len;
+       size = dev->wl->current_beacon->len;
        probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
        if (unlikely(!probe_resp_data))
                return;
@@ -1284,50 +1323,33 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
        /* Looks like PLCP headers plus packet timings are stored for
         * all possible basic rates
         */
-       b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
-       b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
-       b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
-       b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+       b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
+       b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
+       b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
+       b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
 
        size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
        b43_write_template_common(dev, probe_resp_data,
-                                 size, ram_offset, shm_size_offset, rate);
+                                 size, ram_offset, shm_size_offset,
+                                 rate->hw_value);
        kfree(probe_resp_data);
 }
 
-static int b43_refresh_cached_beacon(struct b43_wldev *dev,
-                                    struct sk_buff *beacon)
-{
-       if (dev->cached_beacon)
-               kfree_skb(dev->cached_beacon);
-       dev->cached_beacon = beacon;
-
-       return 0;
-}
-
-static void b43_update_templates(struct b43_wldev *dev)
-{
-       u32 status;
-
-       B43_WARN_ON(!dev->cached_beacon);
-
-       b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-       b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-       b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
-
-       status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
-       status |= 0x03;
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
-}
-
-static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+/* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
 {
-       int err;
+       /* This is the top half of the ansynchronous beacon update.
+        * The bottom half is the beacon IRQ.
+        * Beacon update must be asynchronous to avoid sending an
+        * invalid beacon. This can happen for example, if the firmware
+        * transmits a beacon while we are updating it. */
 
-       err = b43_refresh_cached_beacon(dev, beacon);
-       if (unlikely(err))
-               return;
-       b43_update_templates(dev);
+       if (wl->current_beacon)
+               dev_kfree_skb_any(wl->current_beacon);
+       wl->current_beacon = beacon;
+       wl->beacon0_uploaded = 0;
+       wl->beacon1_uploaded = 0;
 }
 
 static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
@@ -1363,33 +1385,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 
 static void handle_irq_beacon(struct b43_wldev *dev)
 {
-       u32 status;
+       struct b43_wl *wl = dev->wl;
+       u32 cmd;
 
-       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+       if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
                return;
 
-       dev->irq_savedstate &= ~B43_IRQ_BEACON;
-       status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+       /* This is the bottom half of the asynchronous beacon update. */
 
-       if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
-               /* ACK beacon IRQ. */
-               b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
-               dev->irq_savedstate |= B43_IRQ_BEACON;
-               if (dev->cached_beacon)
-                       kfree_skb(dev->cached_beacon);
-               dev->cached_beacon = NULL;
-               return;
-       }
-       if (!(status & 0x1)) {
-               b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-               status |= 0x1;
-               b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+       cmd = b43_read32(dev, B43_MMIO_MACCMD);
+       if (!(cmd & B43_MACCMD_BEACON0_VALID)) {
+               if (!wl->beacon0_uploaded) {
+                       b43_write_beacon_template(dev, 0x68, 0x18,
+                                                 B43_CCK_RATE_1MB);
+                       b43_write_probe_resp_template(dev, 0x268, 0x4A,
+                                                     &__b43_ratetable[3]);
+                       wl->beacon0_uploaded = 1;
+               }
+               cmd |= B43_MACCMD_BEACON0_VALID;
        }
-       if (!(status & 0x2)) {
-               b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-               status |= 0x2;
-               b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+       if (!(cmd & B43_MACCMD_BEACON1_VALID)) {
+               if (!wl->beacon1_uploaded) {
+                       b43_write_beacon_template(dev, 0x468, 0x1A,
+                                                 B43_CCK_RATE_1MB);
+                       wl->beacon1_uploaded = 1;
+               }
+               cmd |= B43_MACCMD_BEACON1_VALID;
        }
+       b43_write32(dev, B43_MMIO_MACCMD, cmd);
 }
 
 static void handle_irq_ucode_debug(struct b43_wldev *dev)
@@ -1419,8 +1442,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
        if (unlikely(reason & B43_IRQ_MAC_TXERR))
                b43err(dev->wl, "MAC transmission error\n");
 
-       if (unlikely(reason & B43_IRQ_PHY_TXERR))
+       if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
                b43err(dev->wl, "PHY transmission error\n");
+               rmb();
+               if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
+                       atomic_set(&dev->phy.txerr_cnt,
+                                  B43_PHY_TX_BADNESS_LIMIT);
+                       b43err(dev->wl, "Too many PHY TX errors, "
+                                       "restarting the controller\n");
+                       b43_controller_restart(dev, "PHY TX errors");
+               }
+       }
 
        if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
                                          B43_DMAIRQ_NONFATALMASK))) {
@@ -1462,20 +1494,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
                handle_irq_noise(dev);
 
        /* Check the DMA reason registers for received data. */
-       if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
-               if (b43_using_pio(dev))
-                       b43_pio_rx(dev->pio.queue0);
-               else
-                       b43_dma_rx(dev->dma.rx_ring0);
-       }
+       if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
+               b43_dma_rx(dev->dma.rx_ring0);
+       if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
+               b43_dma_rx(dev->dma.rx_ring3);
        B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
        B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
-       if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
-               if (b43_using_pio(dev))
-                       b43_pio_rx(dev->pio.queue3);
-               else
-                       b43_dma_rx(dev->dma.rx_ring3);
-       }
        B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
        B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
 
@@ -1487,29 +1511,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
        spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 }
 
-static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
-{
-       u16 rxctl;
-
-       rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
-       if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
-               dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
-       else
-               dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
-}
-
 static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
 {
-       if (b43_using_pio(dev) &&
-           (dev->dev->id.revision < 3) &&
-           (!(reason & B43_IRQ_PIO_WORKAROUND))) {
-               /* Apply a PIO specific workaround to the dma_reasons */
-               pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
-               pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
-               pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
-               pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
-       }
-
        b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
 
        b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
@@ -1568,54 +1571,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
        return ret;
 }
 
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+       release_firmware(fw->data);
+       fw->data = NULL;
+       fw->filename = NULL;
+}
+
 static void b43_release_firmware(struct b43_wldev *dev)
 {
-       release_firmware(dev->fw.ucode);
-       dev->fw.ucode = NULL;
-       release_firmware(dev->fw.pcm);
-       dev->fw.pcm = NULL;
-       release_firmware(dev->fw.initvals);
-       dev->fw.initvals = NULL;
-       release_firmware(dev->fw.initvals_band);
-       dev->fw.initvals_band = NULL;
+       do_release_fw(&dev->fw.ucode);
+       do_release_fw(&dev->fw.pcm);
+       do_release_fw(&dev->fw.initvals);
+       do_release_fw(&dev->fw.initvals_band);
 }
 
-static void b43_print_fw_helptext(struct b43_wl *wl)
+static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
 {
-       b43err(wl, "You must go to "
-              "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
-              "and download the correct firmware (version 4).\n");
+       const char *text;
+
+       text = "You must go to "
+              "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
+              "and download the latest firmware (version 4).\n";
+       if (error)
+               b43err(wl, text);
+       else
+               b43warn(wl, text);
 }
 
 static int do_request_fw(struct b43_wldev *dev,
                         const char *name,
-                        const struct firmware **fw)
+                        struct b43_firmware_file *fw)
 {
        char path[sizeof(modparam_fwpostfix) + 32];
+       const struct firmware *blob;
        struct b43_fw_header *hdr;
        u32 size;
        int err;
 
-       if (!name)
+       if (!name) {
+               /* Don't fetch anything. Free possibly cached firmware. */
+               do_release_fw(fw);
                return 0;
+       }
+       if (fw->filename) {
+               if (strcmp(fw->filename, name) == 0)
+                       return 0; /* Already have this fw. */
+               /* Free the cached firmware first. */
+               do_release_fw(fw);
+       }
 
        snprintf(path, ARRAY_SIZE(path),
                 "b43%s/%s.fw",
                 modparam_fwpostfix, name);
-       err = request_firmware(fw, path, dev->dev->dev);
+       err = request_firmware(&blob, path, dev->dev->dev);
        if (err) {
                b43err(dev->wl, "Firmware file \"%s\" not found "
                       "or load failed.\n", path);
                return err;
        }
-       if ((*fw)->size < sizeof(struct b43_fw_header))
+       if (blob->size < sizeof(struct b43_fw_header))
                goto err_format;
-       hdr = (struct b43_fw_header *)((*fw)->data);
+       hdr = (struct b43_fw_header *)(blob->data);
        switch (hdr->type) {
        case B43_FW_TYPE_UCODE:
        case B43_FW_TYPE_PCM:
                size = be32_to_cpu(hdr->size);
-               if (size != (*fw)->size - sizeof(struct b43_fw_header))
+               if (size != blob->size - sizeof(struct b43_fw_header))
                        goto err_format;
                /* fallthrough */
        case B43_FW_TYPE_IV:
@@ -1626,10 +1648,15 @@ static int do_request_fw(struct b43_wldev *dev,
                goto err_format;
        }
 
-       return err;
+       fw->data = blob;
+       fw->filename = name;
+
+       return 0;
 
 err_format:
        b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+       release_firmware(blob);
+
        return -EPROTO;
 }
 
@@ -1641,90 +1668,101 @@ static int b43_request_firmware(struct b43_wldev *dev)
        u32 tmshigh;
        int err;
 
+       /* Get microcode */
        tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-       if (!fw->ucode) {
+       if ((rev >= 5) && (rev <= 10))
+               filename = "ucode5";
+       else if ((rev >= 11) && (rev <= 12))
+               filename = "ucode11";
+       else if (rev >= 13)
+               filename = "ucode13";
+       else
+               goto err_no_ucode;
+       err = do_request_fw(dev, filename, &fw->ucode);
+       if (err)
+               goto err_load;
+
+       /* Get PCM code */
+       if ((rev >= 5) && (rev <= 10))
+               filename = "pcm5";
+       else if (rev >= 11)
+               filename = NULL;
+       else
+               goto err_no_pcm;
+       err = do_request_fw(dev, filename, &fw->pcm);
+       if (err)
+               goto err_load;
+
+       /* Get initvals */
+       switch (dev->phy.type) {
+       case B43_PHYTYPE_A:
+               if ((rev >= 5) && (rev <= 10)) {
+                       if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+                               filename = "a0g1initvals5";
+                       else
+                               filename = "a0g0initvals5";
+               } else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_G:
                if ((rev >= 5) && (rev <= 10))
-                       filename = "ucode5";
-               else if ((rev >= 11) && (rev <= 12))
-                       filename = "ucode11";
+                       filename = "b0g0initvals5";
                else if (rev >= 13)
-                       filename = "ucode13";
+                       filename = "lp0initvals13";
                else
-                       goto err_no_ucode;
-               err = do_request_fw(dev, filename, &fw->ucode);
-               if (err)
-                       goto err_load;
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_N:
+               if ((rev >= 11) && (rev <= 12))
+                       filename = "n0initvals11";
+               else
+                       goto err_no_initvals;
+               break;
+       default:
+               goto err_no_initvals;
        }
-       if (!fw->pcm) {
+       err = do_request_fw(dev, filename, &fw->initvals);
+       if (err)
+               goto err_load;
+
+       /* Get bandswitch initvals */
+       switch (dev->phy.type) {
+       case B43_PHYTYPE_A:
+               if ((rev >= 5) && (rev <= 10)) {
+                       if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+                               filename = "a0g1bsinitvals5";
+                       else
+                               filename = "a0g0bsinitvals5";
+               } else if (rev >= 11)
+                       filename = NULL;
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_G:
                if ((rev >= 5) && (rev <= 10))
-                       filename = "pcm5";
+                       filename = "b0g0bsinitvals5";
                else if (rev >= 11)
                        filename = NULL;
                else
-                       goto err_no_pcm;
-               err = do_request_fw(dev, filename, &fw->pcm);
-               if (err)
-                       goto err_load;
-       }
-       if (!fw->initvals) {
-               switch (dev->phy.type) {
-               case B43_PHYTYPE_A:
-                       if ((rev >= 5) && (rev <= 10)) {
-                               if (tmshigh & B43_TMSHIGH_GPHY)
-                                       filename = "a0g1initvals5";
-                               else
-                                       filename = "a0g0initvals5";
-                       } else
-                               goto err_no_initvals;
-                       break;
-               case B43_PHYTYPE_G:
-                       if ((rev >= 5) && (rev <= 10))
-                               filename = "b0g0initvals5";
-                       else if (rev >= 13)
-                               filename = "lp0initvals13";
-                       else
-                               goto err_no_initvals;
-                       break;
-               default:
                        goto err_no_initvals;
-               }
-               err = do_request_fw(dev, filename, &fw->initvals);
-               if (err)
-                       goto err_load;
-       }
-       if (!fw->initvals_band) {
-               switch (dev->phy.type) {
-               case B43_PHYTYPE_A:
-                       if ((rev >= 5) && (rev <= 10)) {
-                               if (tmshigh & B43_TMSHIGH_GPHY)
-                                       filename = "a0g1bsinitvals5";
-                               else
-                                       filename = "a0g0bsinitvals5";
-                       } else if (rev >= 11)
-                               filename = NULL;
-                       else
-                               goto err_no_initvals;
-                       break;
-               case B43_PHYTYPE_G:
-                       if ((rev >= 5) && (rev <= 10))
-                               filename = "b0g0bsinitvals5";
-                       else if (rev >= 11)
-                               filename = NULL;
-                       else
-                               goto err_no_initvals;
-                       break;
-               default:
+               break;
+       case B43_PHYTYPE_N:
+               if ((rev >= 11) && (rev <= 12))
+                       filename = "n0bsinitvals11";
+               else
                        goto err_no_initvals;
-               }
-               err = do_request_fw(dev, filename, &fw->initvals_band);
-               if (err)
-                       goto err_load;
+               break;
+       default:
+               goto err_no_initvals;
        }
+       err = do_request_fw(dev, filename, &fw->initvals_band);
+       if (err)
+               goto err_load;
 
        return 0;
 
 err_load:
-       b43_print_fw_helptext(dev->wl);
+       b43_print_fw_helptext(dev->wl, 1);
        goto error;
 
 err_no_ucode:
@@ -1754,22 +1792,33 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        const __be32 *data;
        unsigned int i, len;
        u16 fwrev, fwpatch, fwdate, fwtime;
-       u32 tmp;
+       u32 tmp, macctl;
        int err = 0;
 
+       /* Jump the microcode PSM to offset 0 */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+       /* Zero out all microcode PSM registers and shared memory. */
+       for (i = 0; i < 64; i++)
+               b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+       for (i = 0; i < 4096; i += 2)
+               b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
        /* Upload Microcode. */
-       data = (__be32 *) (dev->fw.ucode->data + hdr_len);
-       len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+       data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+       len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
        b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
        for (i = 0; i < len; i++) {
                b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
                udelay(10);
        }
 
-       if (dev->fw.pcm) {
+       if (dev->fw.pcm.data) {
                /* Upload PCM data. */
-               data = (__be32 *) (dev->fw.pcm->data + hdr_len);
-               len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+               data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+               len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
                b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
                b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
                /* No need for autoinc bit in SHM_HW */
@@ -1781,9 +1830,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        }
 
        b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_RUN |
-                   B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+       /* Start the microcode PSM */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_JMP0;
+       macctl |= B43_MACCTL_PSM_RUN;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        /* Wait for the microcode to load and respond */
        i = 0;
@@ -1792,13 +1844,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                if (tmp == B43_IRQ_MAC_SUSPENDED)
                        break;
                i++;
-               if (i >= 50) {
+               if (i >= 20) {
                        b43err(dev->wl, "Microcode not responding\n");
-                       b43_print_fw_helptext(dev->wl);
+                       b43_print_fw_helptext(dev->wl, 1);
                        err = -ENODEV;
-                       goto out;
+                       goto error;
+               }
+               msleep_interruptible(50);
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       goto error;
                }
-               udelay(10);
        }
        b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);       /* dummy read */
 
@@ -1812,10 +1868,9 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
                       "binary drivers older than version 4.x is unsupported. "
                       "You must upgrade your firmware files.\n");
-               b43_print_fw_helptext(dev->wl);
-               b43_write32(dev, B43_MMIO_MACCTL, 0);
+               b43_print_fw_helptext(dev->wl, 1);
                err = -EOPNOTSUPP;
-               goto out;
+               goto error;
        }
        b43dbg(dev->wl, "Loading firmware version %u.%u "
               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1826,7 +1881,20 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
 
-      out:
+       if (b43_is_old_txhdr_format(dev)) {
+               b43warn(dev->wl, "You are using an old firmware image. "
+                       "Support for old firmware will be removed in July 2008.\n");
+               b43_print_fw_helptext(dev->wl, 0);
+       }
+
+       return 0;
+
+error:
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
        return err;
 }
 
@@ -1886,7 +1954,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
 
 err_format:
        b43err(dev->wl, "Initial Values Firmware file-format error.\n");
-       b43_print_fw_helptext(dev->wl);
+       b43_print_fw_helptext(dev->wl, 1);
 
        return -EPROTO;
 }
@@ -1900,19 +1968,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
        size_t count;
        int err;
 
-       hdr = (const struct b43_fw_header *)(fw->initvals->data);
-       ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+       hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+       ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
        count = be32_to_cpu(hdr->size);
        err = b43_write_initvals(dev, ivals, count,
-                                fw->initvals->size - hdr_len);
+                                fw->initvals.data->size - hdr_len);
        if (err)
                goto out;
-       if (fw->initvals_band) {
-               hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
-               ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+       if (fw->initvals_band.data) {
+               hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+               ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
                count = be32_to_cpu(hdr->size);
                err = b43_write_initvals(dev, ivals, count,
-                                        fw->initvals_band->size - hdr_len);
+                                        fw->initvals_band.data->size - hdr_len);
                if (err)
                        goto out;
        }
@@ -1949,7 +2017,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
@@ -2119,6 +2187,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
        case B43_PHYTYPE_G:
+       case B43_PHYTYPE_N:
                b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -2148,13 +2217,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
        switch (antenna) {
        case B43_ANTENNA0:
-               ant |= B43_TX4_PHY_ANT0;
+               ant |= B43_TXH_PHY_ANT0;
                break;
        case B43_ANTENNA1:
-               ant |= B43_TX4_PHY_ANT1;
+               ant |= B43_TXH_PHY_ANT1;
+               break;
+       case B43_ANTENNA2:
+               ant |= B43_TXH_PHY_ANT2;
+               break;
+       case B43_ANTENNA3:
+               ant |= B43_TXH_PHY_ANT3;
                break;
        case B43_ANTENNA_AUTO:
-               ant |= B43_TX4_PHY_ANTLAST;
+               ant |= B43_TXH_PHY_ANT01AUTO;
                break;
        default:
                B43_WARN_ON(1);
@@ -2164,15 +2239,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
        /* For Beacons */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
        /* For ACK/CTS */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
        /* For Probe Resposes */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
 }
 
@@ -2180,7 +2255,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 static void b43_chip_exit(struct b43_wldev *dev)
 {
        b43_radio_turn_off(dev, 1);
-       b43_leds_exit(dev);
        b43_gpio_cleanup(dev);
        /* firmware is released later */
 }
@@ -2192,11 +2266,15 @@ static int b43_chip_init(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
        int err, tmp;
-       u32 value32;
+       u32 value32, macctl;
        u16 value16;
 
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+       /* Initialize the MAC control */
+       macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+       if (dev->phy.gmode)
+               macctl |= B43_MACCTL_GMODE;
+       macctl |= B43_MACCTL_INFRA;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        err = b43_request_firmware(dev);
        if (err)
@@ -2208,11 +2286,10 @@ static int b43_chip_init(struct b43_wldev *dev)
        err = b43_gpio_init(dev);
        if (err)
                goto out;       /* firmware is released later */
-       b43_leds_init(dev);
 
        err = b43_upload_initvals(dev);
        if (err)
-               goto err_leds_exit;
+               goto err_gpio_clean;
        b43_radio_turn_on(dev);
 
        b43_write16(dev, 0x03E6, 0x0000);
@@ -2242,14 +2319,6 @@ static int b43_chip_init(struct b43_wldev *dev)
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
                    | B43_MACCTL_INFRA);
 
-       if (b43_using_pio(dev)) {
-               b43_write32(dev, 0x0210, 0x00000100);
-               b43_write32(dev, 0x0230, 0x00000100);
-               b43_write32(dev, 0x0250, 0x00000100);
-               b43_write32(dev, 0x0270, 0x00000100);
-               b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
-       }
-
        /* Probe Response Timeout value */
        /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
        b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
@@ -2288,8 +2357,7 @@ out:
 
 err_radio_off:
        b43_radio_turn_off(dev, 1);
-err_leds_exit:
-       b43_leds_exit(dev);
+err_gpio_clean:
        b43_gpio_cleanup(dev);
        return err;
 }
@@ -2312,9 +2380,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
+       if (phy->type != B43_PHYTYPE_G)
+               return;
        if (!b43_has_hardware_pctl(phy))
                b43_lo_g_ctl_mark_all_unused(dev);
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
                b43_mac_suspend(dev);
                b43_calc_nrssi_slope(dev);
                if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
@@ -2366,6 +2436,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
        }
        b43_phy_xmitpower(dev); //FIXME: unless scanning?
        //TODO for APHY (temperature?)
+
+       atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+       wmb();
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -2423,32 +2496,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
        queue_delayed_work(dev->wl->hw->workqueue, work, 0);
 }
 
-/* Validate access to the chip (SHM) */
+/* Check if communication with the device works correctly. */
 static int b43_validate_chipaccess(struct b43_wldev *dev)
 {
-       u32 value;
-       u32 shm_backup;
+       u32 v, backup;
 
-       shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
-       b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
-       if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
-               goto error;
+       backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+
+       /* Check for read/write and endianness problems. */
        b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
        if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
                goto error;
-       b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
-
-       value = b43_read32(dev, B43_MMIO_MACCTL);
-       if ((value | B43_MACCTL_GMODE) !=
-           (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+       b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+       if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
                goto error;
 
-       value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
-       if (value)
+       b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+
+       if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+               /* The 32bit register shadows the two 16bit registers
+                * with update sideeffects. Validate this. */
+               b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
+               b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
+               if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
+                       goto error;
+               if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
+                       goto error;
+       }
+       b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
+
+       v = b43_read32(dev, B43_MMIO_MACCTL);
+       v |= B43_MACCTL_GMODE;
+       if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
                goto error;
 
        return 0;
-      error:
+error:
        b43err(dev->wl, "Failed to validate the chipaccess\n");
        return -ENODEV;
 }
@@ -2511,40 +2594,35 @@ static int b43_rng_init(struct b43_wl *wl)
        return err;
 }
 
-static int b43_tx(struct ieee80211_hw *hw,
-                 struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int b43_op_tx(struct ieee80211_hw *hw,
+                    struct sk_buff *skb,
+                    struct ieee80211_tx_control *ctl)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        int err = -ENODEV;
-       unsigned long flags;
 
        if (unlikely(!dev))
                goto out;
        if (unlikely(b43_status(dev) < B43_STAT_STARTED))
                goto out;
        /* DMA-TX is done without a global lock. */
-       if (b43_using_pio(dev)) {
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               err = b43_pio_tx(dev, skb, ctl);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       } else
-               err = b43_dma_tx(dev, skb, ctl);
-      out:
+       err = b43_dma_tx(dev, skb, ctl);
+out:
        if (unlikely(err))
                return NETDEV_TX_BUSY;
        return NETDEV_TX_OK;
 }
 
-static int b43_conf_tx(struct ieee80211_hw *hw,
-                      int queue,
-                      const struct ieee80211_tx_queue_params *params)
+static int b43_op_conf_tx(struct ieee80211_hw *hw,
+                         int queue,
+                         const struct ieee80211_tx_queue_params *params)
 {
        return 0;
 }
 
-static int b43_get_tx_stats(struct ieee80211_hw *hw,
-                           struct ieee80211_tx_queue_stats *stats)
+static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
+                              struct ieee80211_tx_queue_stats *stats)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2555,19 +2633,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw,
                goto out;
        spin_lock_irqsave(&wl->irq_lock, flags);
        if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
-               if (b43_using_pio(dev))
-                       b43_pio_get_tx_stats(dev, stats);
-               else
-                       b43_dma_get_tx_stats(dev, stats);
+               b43_dma_get_tx_stats(dev, stats);
                err = 0;
        }
        spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out:
+out:
        return err;
 }
 
-static int b43_get_stats(struct ieee80211_hw *hw,
-                        struct ieee80211_low_level_stats *stats)
+static int b43_op_get_stats(struct ieee80211_hw *hw,
+                           struct ieee80211_low_level_stats *stats)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        unsigned long flags;
@@ -2706,8 +2781,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
        return err;
 }
 
-static int b43_antenna_from_ieee80211(u8 antenna)
+/* Check if the use of the antenna that ieee80211 told us to
+ * use is possible. This will fall back to DEFAULT.
+ * "antenna_nr" is the antenna identifier we got from ieee80211. */
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+                                 u8 antenna_nr)
 {
+       u8 antenna_mask;
+
+       if (antenna_nr == 0) {
+               /* Zero means "use default antenna". That's always OK. */
+               return 0;
+       }
+
+       /* Get the mask of available antennas. */
+       if (dev->phy.gmode)
+               antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+       else
+               antenna_mask = dev->dev->bus->sprom.ant_available_a;
+
+       if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
+               /* This antenna is not available. Fall back to default. */
+               return 0;
+       }
+
+       return antenna_nr;
+}
+
+static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
+{
+       antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
        switch (antenna) {
        case 0:         /* default/diversity */
                return B43_ANTENNA_DEFAULT;
@@ -2715,37 +2818,34 @@ static int b43_antenna_from_ieee80211(u8 antenna)
                return B43_ANTENNA0;
        case 2:         /* Antenna 1 */
                return B43_ANTENNA1;
+       case 3:         /* Antenna 2 */
+               return B43_ANTENNA2;
+       case 4:         /* Antenna 3 */
+               return B43_ANTENNA3;
        default:
                return B43_ANTENNA_DEFAULT;
        }
 }
 
-static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
        struct b43_phy *phy;
        unsigned long flags;
        unsigned int new_phymode = 0xFFFF;
-       int antenna_tx;
-       int antenna_rx;
+       int antenna;
        int err = 0;
        u32 savedirqs;
 
-       antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
-       antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
-
        mutex_lock(&wl->mutex);
 
        /* Switch the PHY mode (if necessary). */
-       switch (conf->phymode) {
-       case MODE_IEEE80211A:
+       switch (conf->channel->band) {
+       case IEEE80211_BAND_5GHZ:
                new_phymode = B43_PHYMODE_A;
                break;
-       case MODE_IEEE80211B:
-               new_phymode = B43_PHYMODE_B;
-               break;
-       case MODE_IEEE80211G:
+       case IEEE80211_BAND_2GHZ:
                new_phymode = B43_PHYMODE_G;
                break;
        default:
@@ -2771,8 +2871,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 
        /* Switch to the requested channel.
         * The firmware takes care of races with the TX handler. */
-       if (conf->channel_val != phy->channel)
-               b43_radio_selectchannel(dev, conf->channel_val, 0);
+       if (conf->channel->hw_value != phy->channel)
+               b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
 
        /* Enable/Disable ShortSlot timing. */
        if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
@@ -2784,6 +2884,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
                        b43_short_slot_timing_disable(dev);
        }
 
+       dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
        /* Adjust the desired TX power level. */
        if (conf->power_level != 0) {
                if (conf->power_level != phy->power_level) {
@@ -2793,8 +2895,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
        }
 
        /* Antennas for RX and management frame TX. */
-       b43_mgmtframe_txantenna(dev, antenna_tx);
-       b43_set_rx_antenna(dev, antenna_rx);
+       antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+       b43_mgmtframe_txantenna(dev, antenna);
+       antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+       b43_set_rx_antenna(dev, antenna);
 
        /* Update templates for AP mode. */
        if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
@@ -2825,22 +2929,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
        return err;
 }
 
-static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           const u8 *local_addr, const u8 *addr,
                           struct ieee80211_key_conf *key)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
-       struct b43_wldev *dev = wl->current_dev;
+       struct b43_wldev *dev;
        unsigned long flags;
        u8 algorithm;
        u8 index;
-       int err = -EINVAL;
+       int err;
+       DECLARE_MAC_BUF(mac);
 
        if (modparam_nohwcrypt)
                return -ENOSPC; /* User disabled HW-crypto */
 
-       if (!dev)
-               return -ENODEV;
+       mutex_lock(&wl->mutex);
+       spin_lock_irqsave(&wl->irq_lock, flags);
+
+       dev = wl->current_dev;
+       err = -ENODEV;
+       if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+               goto out_unlock;
+
+       err = -EINVAL;
        switch (key->alg) {
        case ALG_WEP:
                if (key->keylen == 5)
@@ -2856,20 +2968,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        default:
                B43_WARN_ON(1);
-               goto out;
+               goto out_unlock;
        }
-
        index = (u8) (key->keyidx);
        if (index > 3)
-               goto out;
-
-       mutex_lock(&wl->mutex);
-       spin_lock_irqsave(&wl->irq_lock, flags);
-
-       if (b43_status(dev) < B43_STAT_INITIALIZED) {
-               err = -ENODEV;
                goto out_unlock;
-       }
 
        switch (cmd) {
        case SET_KEY:
@@ -2915,19 +3018,18 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 out_unlock:
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        mutex_unlock(&wl->mutex);
-out:
        if (!err) {
                b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
-                      "mac: " MAC_FMT "\n",
+                      "mac: %s\n",
                       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
-                      MAC_ARG(addr));
+                      print_mac(mac, addr));
        }
        return err;
 }
 
-static void b43_configure_filter(struct ieee80211_hw *hw,
-                                unsigned int changed, unsigned int *fflags,
-                                int mc_count, struct dev_addr_list *mc_list)
+static void b43_op_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed, unsigned int *fflags,
+                                   int mc_count, struct dev_addr_list *mc_list)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2962,8 +3064,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw,
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
-static int b43_config_interface(struct ieee80211_hw *hw,
-                               int if_id, struct ieee80211_if_conf *conf)
+static int b43_op_config_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_if_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2973,7 +3076,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
                return -ENODEV;
        mutex_lock(&wl->mutex);
        spin_lock_irqsave(&wl->irq_lock, flags);
-       B43_WARN_ON(wl->if_id != if_id);
+       B43_WARN_ON(wl->vif != vif);
        if (conf->bssid)
                memcpy(wl->bssid, conf->bssid, ETH_ALEN);
        else
@@ -2983,7 +3086,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
                        B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
                        b43_set_ssid(dev, conf->ssid, conf->ssid_len);
                        if (conf->beacon)
-                               b43_refresh_templates(dev, conf->beacon);
+                               b43_update_templates(wl, conf->beacon);
                }
                b43_write_mac_bssid_templates(dev);
        }
@@ -3001,6 +3104,16 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
        if (b43_status(dev) < B43_STAT_STARTED)
                return;
+
+       /* Disable and sync interrupts. We must do this before than
+        * setting the status to INITIALIZED, as the interrupt handler
+        * won't care about IRQs then. */
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+       b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       b43_synchronize_irq(dev);
+
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
        mutex_unlock(&wl->mutex);
@@ -3011,13 +3124,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
        ieee80211_stop_queues(wl->hw);  //FIXME this could cause a deadlock, as mac80211 seems buggy.
 
-       /* Disable and sync interrupts. */
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
-       b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-       b43_synchronize_irq(dev);
-
        b43_mac_suspend(dev);
        free_irq(dev->dev->irq, dev);
        b43dbg(wl, "Wireless interface stopped\n");
@@ -3083,9 +3189,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        unsupported = 1;
                break;
        case B43_PHYTYPE_G:
-               if (phy_rev > 8)
+               if (phy_rev > 9)
+                       unsupported = 1;
+               break;
+#ifdef CONFIG_B43_NPHY
+       case B43_PHYTYPE_N:
+               if (phy_rev > 1)
                        unsupported = 1;
                break;
+#endif
        default:
                unsupported = 1;
        };
@@ -3108,14 +3220,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        tmp = 0x5205017F;
        } else {
                b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
-               tmp <<= 16;
+               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
                b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+               tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
        }
        radio_manuf = (tmp & 0x00000FFF);
        radio_ver = (tmp & 0x0FFFF000) >> 12;
        radio_rev = (tmp & 0xF0000000) >> 28;
+       if (radio_manuf != 0x17F /* Broadcom */)
+               unsupported = 1;
        switch (phy_type) {
        case B43_PHYTYPE_A:
                if (radio_ver != 0x2060)
@@ -3133,6 +3246,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (radio_ver != 0x2050)
                        unsupported = 1;
                break;
+       case B43_PHYTYPE_N:
+               if (radio_ver != 0x2055)
+                       unsupported = 1;
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -3165,9 +3282,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
        memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
 
-       /* Flags */
-       phy->locked = 0;
-
        phy->aci_enable = 0;
        phy->aci_wlan_automatic = 0;
        phy->aci_hw_rssi = 0;
@@ -3194,17 +3308,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        phy->lofcal = 0xFFFF;
        phy->initval = 0xFFFF;
 
-       spin_lock_init(&phy->lock);
        phy->interfmode = B43_INTERFMODE_NONE;
        phy->channel = 0xFF;
 
        phy->hardware_power_control = !!modparam_hwpctl;
+
+       /* PHY TX errors counter. */
+       atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+       /* OFDM-table address caching. */
+       phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 {
-       /* Flags */
-       dev->reg124_set_0x4 = 0;
+       dev->dfq_valid = 0;
+
        /* Assume the radio is enabled. If it's not enabled, the state will
         * immediately get fixed on the first periodic work run. */
        dev->radio_hw_enable = 1;
@@ -3230,13 +3349,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
        struct ssb_sprom *sprom = &dev->dev->bus->sprom;
        u32 hf;
 
-       if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+       if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
                return;
        if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
                return;
 
        hf = b43_hf_read(dev);
-       if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+       if (sprom->boardflags_lo & B43_BFL_BTCMOD)
                hf |= B43_HF_BTCOEXALT;
        else
                hf |= B43_HF_BTCOEX;
@@ -3275,23 +3394,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+                                unsigned int short_retry,
+                                unsigned int long_retry)
+{
+       /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+        * the chip-internal counter. */
+       short_retry = min(short_retry, (unsigned int)0xF);
+       long_retry = min(long_retry, (unsigned int)0xF);
+
+       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+                       short_retry);
+       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+                       long_retry);
+}
+
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
+       u32 macctl;
 
        B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
        if (b43_status(dev) != B43_STAT_INITIALIZED)
                return;
        b43_set_status(dev, B43_STAT_UNINIT);
 
-       mutex_unlock(&dev->wl->mutex);
-       b43_rfkill_exit(dev);
-       mutex_lock(&dev->wl->mutex);
+       /* Stop the microcode PSM. */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
+       b43_leds_exit(dev);
        b43_rng_exit(dev->wl);
-       b43_pio_free(dev);
        b43_dma_free(dev);
        b43_chip_exit(dev);
        b43_radio_turn_off(dev, 1);
@@ -3300,6 +3438,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                kfree(phy->tssi2dbm);
        kfree(phy->lo_control);
        phy->lo_control = NULL;
+       if (dev->wl->current_beacon) {
+               dev_kfree_skb_any(dev->wl->current_beacon);
+               dev->wl->current_beacon = NULL;
+       }
+
        ssb_device_disable(dev->dev, 0);
        ssb_bus_may_powerdown(dev->dev->bus);
 }
@@ -3354,7 +3497,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
                hf |= B43_HF_SYMW;
                if (phy->rev == 1)
                        hf |= B43_HF_GDCW;
-               if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+               if (sprom->boardflags_lo & B43_BFL_PACTRL)
                        hf |= B43_HF_OFDMPABOOST;
        } else if (phy->type == B43_PHYTYPE_B) {
                hf |= B43_HF_SYMW;
@@ -3363,15 +3506,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        }
        b43_hf_write(dev, hf);
 
-       /* Short/Long Retry Limit.
-        * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
-        * the chip-internal counter.
-        */
-       tmp = limit_value(modparam_short_retry, 0, 0xF);
-       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
-       tmp = limit_value(modparam_long_retry, 0, 0xF);
-       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
-
+       b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
+                            B43_DEFAULT_LONG_RETRY_LIMIT);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
 
@@ -3392,17 +3528,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       do {
-               if (b43_using_pio(dev)) {
-                       err = b43_pio_init(dev);
-               } else {
-                       err = b43_dma_init(dev);
-                       if (!err)
-                               b43_qos_init(dev);
-               }
-       } while (err == -EAGAIN);
+       err = b43_dma_init(dev);
        if (err)
                goto err_chip_exit;
+       b43_qos_init(dev);
 
 //FIXME
 #if 1
@@ -3414,16 +3543,14 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_bluetooth_coext_enable(dev);
 
        ssb_bus_powerup(bus, 1);        /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       b43_rfkill_init(dev);
        b43_rng_init(wl);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-      out:
+       b43_leds_init(dev);
+out:
        return err;
 
       err_chip_exit:
@@ -3440,8 +3567,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        return err;
 }
 
-static int b43_add_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_if_init_conf *conf)
+static int b43_op_add_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_if_init_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -3464,7 +3591,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 
        dev = wl->current_dev;
        wl->operating = 1;
-       wl->if_id = conf->if_id;
+       wl->vif = conf->vif;
        wl->if_type = conf->type;
        memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
 
@@ -3480,8 +3607,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
        return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf)
+static void b43_op_remove_interface(struct ieee80211_hw *hw,
+                                   struct ieee80211_if_init_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -3492,7 +3619,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
 
        B43_WARN_ON(!wl->operating);
-       B43_WARN_ON(wl->if_id != conf->if_id);
+       B43_WARN_ON(wl->vif != conf->vif);
+       wl->vif = NULL;
 
        wl->operating = 0;
 
@@ -3505,19 +3633,34 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
        mutex_unlock(&wl->mutex);
 }
 
-static int b43_start(struct ieee80211_hw *hw)
+static int b43_op_start(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
+       bool do_rfkill_exit = 0;
+
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+       wl->radiotap_enabled = 0;
+
+       /* First register RFkill.
+        * LEDs that are registered later depend on it. */
+       b43_rfkill_init(dev);
 
        mutex_lock(&wl->mutex);
 
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
-               if (err)
+               if (err) {
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
+               }
                did_init = 1;
        }
 
@@ -3526,6 +3669,7 @@ static int b43_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43_wireless_core_exit(dev);
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
@@ -3533,14 +3677,19 @@ static int b43_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
+       if (do_rfkill_exit)
+               b43_rfkill_exit(dev);
+
        return err;
 }
 
-static void b43_stop(struct ieee80211_hw *hw)
+static void b43_op_stop(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
 
+       b43_rfkill_exit(dev);
+
        mutex_lock(&wl->mutex);
        if (b43_status(dev) >= B43_STAT_STARTED)
                b43_wireless_core_stop(dev);
@@ -3548,19 +3697,76 @@ static void b43_stop(struct ieee80211_hw *hw)
        mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
+                                 u32 short_retry_limit, u32 long_retry_limit)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+       int err = 0;
+
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
+               err = -ENODEV;
+               goto out_unlock;
+       }
+       b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+out_unlock:
+       mutex_unlock(&wl->mutex);
+
+       return err;
+}
+
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct sk_buff *beacon;
+       unsigned long flags;
+
+       /* We could modify the existing beacon and set the aid bit in
+        * the TIM field, but that would probably require resizing and
+        * moving of data within the beacon template.
+        * Simply request a new beacon and let mac80211 do the hard work. */
+       beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+       if (unlikely(!beacon))
+               return -ENOMEM;
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_update_templates(wl, beacon);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       return 0;
+}
+
+static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
+                                    struct sk_buff *beacon,
+                                    struct ieee80211_tx_control *ctl)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_update_templates(wl, beacon);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
-       .tx = b43_tx,
-       .conf_tx = b43_conf_tx,
-       .add_interface = b43_add_interface,
-       .remove_interface = b43_remove_interface,
-       .config = b43_dev_config,
-       .config_interface = b43_config_interface,
-       .configure_filter = b43_configure_filter,
-       .set_key = b43_dev_set_key,
-       .get_stats = b43_get_stats,
-       .get_tx_stats = b43_get_tx_stats,
-       .start = b43_start,
-       .stop = b43_stop,
+       .tx                     = b43_op_tx,
+       .conf_tx                = b43_op_conf_tx,
+       .add_interface          = b43_op_add_interface,
+       .remove_interface       = b43_op_remove_interface,
+       .config                 = b43_op_config,
+       .config_interface       = b43_op_config_interface,
+       .configure_filter       = b43_op_configure_filter,
+       .set_key                = b43_op_set_key,
+       .get_stats              = b43_op_get_stats,
+       .get_tx_stats           = b43_op_get_tx_stats,
+       .start                  = b43_op_start,
+       .stop                   = b43_op_stop,
+       .set_retry_limit        = b43_op_set_retry_limit,
+       .set_tim                = b43_op_beacon_set_tim,
+       .beacon_update          = b43_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3605,79 +3811,26 @@ static void b43_chip_reset(struct work_struct *work)
 }
 
 static int b43_setup_modes(struct b43_wldev *dev,
-                          int have_aphy, int have_bphy, int have_gphy)
+                          bool have_2ghz_phy, bool have_5ghz_phy)
 {
        struct ieee80211_hw *hw = dev->wl->hw;
-       struct ieee80211_hw_mode *mode;
        struct b43_phy *phy = &dev->phy;
-       int cnt = 0;
-       int err;
 
-/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
-       have_aphy = 0;
-
-       phy->possible_phymodes = 0;
-       for (; 1; cnt++) {
-               if (have_aphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211A;
-                       mode->num_channels = b43_a_chantable_size;
-                       mode->channels = b43_a_chantable;
-                       mode->num_rates = b43_a_ratetable_size;
-                       mode->rates = b43_a_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_A;
-                       have_aphy = 0;
-                       continue;
-               }
-               if (have_bphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211B;
-                       mode->num_channels = b43_bg_chantable_size;
-                       mode->channels = b43_bg_chantable;
-                       mode->num_rates = b43_b_ratetable_size;
-                       mode->rates = b43_b_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_B;
-                       have_bphy = 0;
-                       continue;
-               }
-               if (have_gphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211G;
-                       mode->num_channels = b43_bg_chantable_size;
-                       mode->channels = b43_bg_chantable;
-                       mode->num_rates = b43_g_ratetable_size;
-                       mode->rates = b43_g_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_G;
-                       have_gphy = 0;
-                       continue;
-               }
-               break;
-       }
+       /* XXX: This function will go away soon, when mac80211
+        *      band stuff is rewritten. So this is just a hack.
+        *      For now we always claim GPHY mode, as there is no
+        *      support for NPHY and APHY in the device, yet.
+        *      This assumption is OK, as any B, N or A PHY will already
+        *      have died a horrible sanity check death earlier. */
+
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
+       phy->possible_phymodes |= B43_PHYMODE_G;
 
        return 0;
 }
 
 static void b43_wireless_core_detach(struct b43_wldev *dev)
 {
-       b43_rfkill_free(dev);
        /* We release firmware that late to not be required to re-request
         * is all the time when we reinit the core. */
        b43_release_firmware(dev);
@@ -3689,7 +3842,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        struct ssb_bus *bus = dev->dev->bus;
        struct pci_dev *pdev = bus->host_pci;
        int err;
-       int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+       bool have_2ghz_phy = 0, have_5ghz_phy = 0;
        u32 tmp;
 
        /* Do NOT do any device initialization here.
@@ -3709,17 +3862,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                u32 tmshigh;
 
                tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-               have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
-               have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
-               if (!have_aphy && !have_gphy)
-                       have_bphy = 1;
-       } else if (dev->dev->id.revision == 4) {
-               have_gphy = 1;
-               have_aphy = 1;
+               have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+               have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
        } else
-               have_bphy = 1;
+               B43_WARN_ON(1);
 
-       dev->phy.gmode = (have_gphy || have_bphy);
+       dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
@@ -3731,31 +3879,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
            (pdev->device != 0x4312 &&
             pdev->device != 0x4319 && pdev->device != 0x4324)) {
                /* No multiband support. */
-               have_aphy = 0;
-               have_bphy = 0;
-               have_gphy = 0;
+               have_2ghz_phy = 0;
+               have_5ghz_phy = 0;
                switch (dev->phy.type) {
                case B43_PHYTYPE_A:
-                       have_aphy = 1;
-                       break;
-               case B43_PHYTYPE_B:
-                       have_bphy = 1;
+                       have_5ghz_phy = 1;
                        break;
                case B43_PHYTYPE_G:
-                       have_gphy = 1;
+               case B43_PHYTYPE_N:
+                       have_2ghz_phy = 1;
                        break;
                default:
                        B43_WARN_ON(1);
                }
        }
-       dev->phy.gmode = (have_gphy || have_bphy);
+       if (dev->phy.type == B43_PHYTYPE_A) {
+               /* FIXME */
+               b43err(wl, "IEEE 802.11a devices are unsupported\n");
+               err = -EOPNOTSUPP;
+               goto err_powerdown;
+       }
+       dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
        err = b43_validate_chipaccess(dev);
        if (err)
                goto err_powerdown;
-       err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+       err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
        if (err)
                goto err_powerdown;
 
@@ -3763,7 +3914,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        if (!wl->current_dev)
                wl->current_dev = dev;
        INIT_WORK(&dev->restart_work, b43_chip_reset);
-       b43_rfkill_alloc(dev);
 
        b43_radio_turn_off(dev, 1);
        b43_switch_analog(dev, 0);
@@ -3827,8 +3977,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
        tasklet_init(&wldev->isr_tasklet,
                     (void (*)(unsigned long))b43_interrupt_tasklet,
                     (unsigned long)wldev);
-       if (modparam_pio)
-               wldev->__using_pio = 1;
        INIT_LIST_HEAD(&wldev->list);
 
        err = b43_wireless_core_attach(wldev);
@@ -3853,20 +4001,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
        /* boardflags workarounds */
        if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
            bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
-               bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+               bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
        if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
            bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
-               bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
-
-       /* Handle case when gain is not set in sprom */
-       if (bus->sprom.r1.antenna_gain_a == 0xFF)
-               bus->sprom.r1.antenna_gain_a = 2;
-       if (bus->sprom.r1.antenna_gain_bg == 0xFF)
-               bus->sprom.r1.antenna_gain_bg = 2;
-
-       /* Convert Antennagain values to Q5.2 */
-       bus->sprom.r1.antenna_gain_a <<= 2;
-       bus->sprom.r1.antenna_gain_bg <<= 2;
+               bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
@@ -3893,16 +4031,17 @@ static int b43_wireless_init(struct ssb_device *dev)
        }
 
        /* fill hw info */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+                   IEEE80211_HW_RX_INCLUDES_FCS;
        hw->max_signal = 100;
        hw->max_rssi = -110;
        hw->max_noise = -110;
        hw->queues = 1;         /* FIXME: hardware has more queues */
        SET_IEEE80211_DEV(hw, dev->dev);
-       if (is_valid_ether_addr(sprom->r1.et1mac))
-               SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+       if (is_valid_ether_addr(sprom->et1mac))
+               SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
        else
-               SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+               SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
        /* Get and initialize struct b43_wl */
        wl = hw_to_b43_wl(hw);
@@ -3910,6 +4049,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        wl->hw = hw;
        spin_lock_init(&wl->irq_lock);
        spin_lock_init(&wl->leds_lock);
+       spin_lock_init(&wl->shm_lock);
        mutex_init(&wl->mutex);
        INIT_LIST_HEAD(&wl->devlist);
 
@@ -4053,16 +4193,6 @@ static struct ssb_driver b43_ssb_driver = {
        .resume         = b43_resume,
 };
 
-inline int b43_pci_ssb_bridge_init(void)
-{
-       return ssb_pcihost_register(&b43_pci_bridge_driver);
-}
-
-inline void b43_pci_ssb_bridge_exit(void)
-{
-       ssb_pcihost_unregister(&b43_pci_bridge_driver);
-}
-
 static int __init b43_init(void)
 {
        int err;
@@ -4071,19 +4201,12 @@ static int __init b43_init(void)
        err = b43_pcmcia_init();
        if (err)
                goto err_dfs_exit;
-
-       err = b43_pci_ssb_bridge_init();
-       if (err)
-               goto err_pcmcia_exit;
-
        err = ssb_driver_register(&b43_ssb_driver);
        if (err)
-               goto err_pci_exit;
+               goto err_pcmcia_exit;
 
        return err;
 
-err_pci_exit:
-       b43_pci_ssb_bridge_exit();
 err_pcmcia_exit:
        b43_pcmcia_exit();
 err_dfs_exit:
@@ -4094,7 +4217,6 @@ err_dfs_exit:
 static void __exit b43_exit(void)
 {
        ssb_driver_unregister(&b43_ssb_driver);
-       b43_pci_ssb_bridge_exit();
        b43_pcmcia_exit();
        b43_debugfs_exit();
 }
index 284d17da17d1ae73c56deb79e389697cf69c9068..2d52d9de93052ecf82d775d7ccf1a05fd8cdf0d8 100644 (file)
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-                     Stefano Brivio <st3@riseup.net>
+                     Stefano Brivio <stefano.brivio@polimi.it>
                      Michael Buesch <mb@bu3sch.de>
                      Danny van Dyk <kugelfang@gentoo.org>
                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
 #define PAD_BYTES(nr_bytes)            P4D_BYTES( __LINE__ , (nr_bytes))
 
 /* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline u8 b43_freq_to_channel_a(int freq)
+static inline u8 b43_freq_to_channel_5ghz(int freq)
 {
        return ((freq - 5000) / 5);
 }
-static inline u8 b43_freq_to_channel_bg(int freq)
+static inline u8 b43_freq_to_channel_2ghz(int freq)
 {
        u8 channel;
 
@@ -54,19 +54,13 @@ static inline u8 b43_freq_to_channel_bg(int freq)
 
        return channel;
 }
-static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
-{
-       if (dev->phy.type == B43_PHYTYPE_A)
-               return b43_freq_to_channel_a(freq);
-       return b43_freq_to_channel_bg(freq);
-}
 
 /* Lightweight function to convert a channel number to a frequency (in Mhz). */
-static inline int b43_channel_to_freq_a(u8 channel)
+static inline int b43_channel_to_freq_5ghz(u8 channel)
 {
        return (5000 + (5 * channel));
 }
-static inline int b43_channel_to_freq_bg(u8 channel)
+static inline int b43_channel_to_freq_2ghz(u8 channel)
 {
        int freq;
 
@@ -77,12 +71,6 @@ static inline int b43_channel_to_freq_bg(u8 channel)
 
        return freq;
 }
-static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
-{
-       if (dev->phy.type == B43_PHYTYPE_A)
-               return b43_channel_to_freq_a(channel);
-       return b43_channel_to_freq_bg(channel);
-}
 
 static inline int b43_is_cck_rate(int rate)
 {
@@ -96,6 +84,9 @@ static inline int b43_is_ofdm_rate(int rate)
        return !b43_is_cck_rate(rate);
 }
 
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+                                 u8 antenna_nr);
+
 void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
 
diff --git a/package/b43/src/nphy.c b/package/b43/src/nphy.c
new file mode 100644 (file)
index 0000000..705131e
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY support
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "nphy.h"
+#include "tables_nphy.h"
+
+#include <linux/delay.h>
+
+
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
+{//TODO
+}
+
+void b43_nphy_xmitpower(struct b43_wldev *dev)
+{//TODO
+}
+
+static void b43_chantab_radio_upload(struct b43_wldev *dev,
+                                    const struct b43_nphy_channeltab_entry *e)
+{
+       b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
+       b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+       b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+       b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+       b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+       b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+       b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+       b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+       b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+       b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+       b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+       b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+       b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+       b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+       b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+       b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+       b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+       b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+       b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+       b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+       b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+       b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
+}
+
+static void b43_chantab_phy_upload(struct b43_wldev *dev,
+                                  const struct b43_nphy_channeltab_entry *e)
+{
+       b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
+       b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
+       b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
+       b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
+       b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
+       b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+}
+
+static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
+{
+       //TODO
+}
+
+/* Tune the hardware to a new channel. Don't call this directly.
+ * Use b43_radio_selectchannel() */
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
+{
+       const struct b43_nphy_channeltab_entry *tabent;
+
+       tabent = b43_nphy_get_chantabent(dev, channel);
+       if (!tabent)
+               return -ESRCH;
+
+       //FIXME enable/disable band select upper20 in RXCTL
+       if (0 /*FIXME 5Ghz*/)
+               b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
+       else
+               b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
+       b43_chantab_radio_upload(dev, tabent);
+       udelay(50);
+       b43_radio_write16(dev, B2055_VCO_CAL10, 5);
+       b43_radio_write16(dev, B2055_VCO_CAL10, 45);
+       b43_radio_write16(dev, B2055_VCO_CAL10, 65);
+       udelay(300);
+       if (0 /*FIXME 5Ghz*/)
+               b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
+       else
+               b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
+       b43_chantab_phy_upload(dev, tabent);
+       b43_nphy_tx_power_fix(dev);
+
+       return 0;
+}
+
+static void b43_radio_init2055_pre(struct b43_wldev *dev)
+{
+       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                    ~B43_NPHY_RFCTL_CMD_PORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                   B43_NPHY_RFCTL_CMD_CHIP0PU |
+                   B43_NPHY_RFCTL_CMD_OEPORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                   B43_NPHY_RFCTL_CMD_PORFORCE);
+}
+
+static void b43_radio_init2055_post(struct b43_wldev *dev)
+{
+       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+       int i;
+       u16 val;
+
+       b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
+       msleep(1);
+       if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+               if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
+                   (binfo->type != 0x46D) ||
+                   (binfo->rev < 0x41)) {
+                       b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+                       b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+                       msleep(1);
+               }
+       }
+       b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
+       msleep(1);
+       b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
+       msleep(1);
+       b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
+       msleep(1);
+       b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
+       msleep(1);
+       b43_radio_set(dev, B2055_CAL_MISC, 0x1);
+       msleep(1);
+       b43_radio_set(dev, B2055_CAL_MISC, 0x40);
+       msleep(1);
+       for (i = 0; i < 100; i++) {
+               val = b43_radio_read16(dev, B2055_CAL_COUT2);
+               if (val & 0x80)
+                       break;
+               udelay(10);
+       }
+       msleep(1);
+       b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
+       msleep(1);
+       b43_radio_selectchannel(dev, dev->phy.channel, 0);
+       b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
+       b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
+       b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+       b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+}
+
+/* Initialize a Broadcom 2055 N-radio */
+static void b43_radio_init2055(struct b43_wldev *dev)
+{
+       b43_radio_init2055_pre(dev);
+       if (b43_status(dev) < B43_STAT_INITIALIZED)
+               b2055_upload_inittab(dev, 0, 1);
+       else
+               b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
+       b43_radio_init2055_post(dev);
+}
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev)
+{
+       b43_radio_init2055(dev);
+}
+
+void b43_nphy_radio_turn_off(struct b43_wldev *dev)
+{
+       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                    ~B43_NPHY_RFCTL_CMD_EN);
+}
+
+#define ntab_upload(dev, offset, data) do { \
+               unsigned int i;                                         \
+               for (i = 0; i < (offset##_SIZE); i++)                   \
+                       b43_ntab_write(dev, (offset) + i, (data)[i]);   \
+       } while (0)
+
+/* Upload the N-PHY tables. */
+static void b43_nphy_tables_init(struct b43_wldev *dev)
+{
+       /* Static tables */
+       ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+       ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+       ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+       ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+       ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+       ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+       ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+       ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+       ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+       ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+       ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+       ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+       ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+       ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+       /* Volatile tables */
+       ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+       ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+       ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+       ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+       ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+       ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+       ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+       ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+       ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+       ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+       ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+       ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       unsigned int i;
+
+       b43_phy_set(dev, B43_NPHY_IQFLIP,
+                   B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+       //FIXME the following condition is different in the specs.
+       if (1 /* FIXME band is 2.4GHz */) {
+               b43_phy_set(dev, B43_NPHY_CLASSCTL,
+                           B43_NPHY_CLASSCTL_CCKEN);
+       } else {
+               b43_phy_mask(dev, B43_NPHY_CLASSCTL,
+                            ~B43_NPHY_CLASSCTL_CCKEN);
+       }
+       b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+       b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
+
+       /* Fixup some tables */
+       b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
+
+       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+       //TODO set RF sequence
+
+       /* Set narrowband clip threshold */
+       b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
+       b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
+
+       /* Set wideband clip 2 threshold */
+       b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+                       ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+                       21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
+       b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+                       ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+                       21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
+
+       /* Set Clip 2 detect */
+       b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+                   B43_NPHY_C1_CGAINI_CL2DETECT);
+       b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+                   B43_NPHY_C2_CGAINI_CL2DETECT);
+
+       if (0 /*FIXME*/) {
+               /* Set dwell lengths */
+               b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
+               b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
+               b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
+               b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
+
+               /* Set gain backoff */
+               b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+                               ~B43_NPHY_C1_CGAINI_GAINBKOFF,
+                               1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
+               b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+                               ~B43_NPHY_C2_CGAINI_GAINBKOFF,
+                               1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+
+               /* Set HPVGA2 index */
+               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
+                               6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
+                               6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+               //FIXME verify that the specs really mean to use autoinc here.
+               for (i = 0; i < 3; i++)
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+       }
+
+       /* Set minimum gain value */
+       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
+                       ~B43_NPHY_C1_MINGAIN,
+                       23 << B43_NPHY_C1_MINGAIN_SHIFT);
+       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
+                       ~B43_NPHY_C2_MINGAIN,
+                       23 << B43_NPHY_C2_MINGAIN_SHIFT);
+
+       if (phy->rev < 2) {
+               b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+                            ~B43_NPHY_SCRAM_SIGCTL_SCM);
+       }
+
+       /* Set phase track alpha and beta */
+       b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+       b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+       b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+       b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+       b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+       b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+}
+
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+       u16 bbcfg;
+
+       ssb_write32(dev->dev, SSB_TMSLOW,
+                   ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+       bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+       b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
+       b43_phy_write(dev, B43_NPHY_BBCFG,
+                     bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+       ssb_write32(dev->dev, SSB_TMSLOW,
+                   ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+}
+
+enum b43_nphy_rf_sequence {
+       B43_RFSEQ_RX2TX,
+       B43_RFSEQ_TX2RX,
+       B43_RFSEQ_RESET2RX,
+       B43_RFSEQ_UPDATE_GAINH,
+       B43_RFSEQ_UPDATE_GAINL,
+       B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+                                      enum b43_nphy_rf_sequence seq)
+{
+       static const u16 trigger[] = {
+               [B43_RFSEQ_RX2TX]               = B43_NPHY_RFSEQTR_RX2TX,
+               [B43_RFSEQ_TX2RX]               = B43_NPHY_RFSEQTR_TX2RX,
+               [B43_RFSEQ_RESET2RX]            = B43_NPHY_RFSEQTR_RST2RX,
+               [B43_RFSEQ_UPDATE_GAINH]        = B43_NPHY_RFSEQTR_UPGH,
+               [B43_RFSEQ_UPDATE_GAINL]        = B43_NPHY_RFSEQTR_UPGL,
+               [B43_RFSEQ_UPDATE_GAINU]        = B43_NPHY_RFSEQTR_UPGU,
+       };
+       int i;
+
+       B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
+
+       b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+                   B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+       b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+       for (i = 0; i < 200; i++) {
+               if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+                       goto ok;
+               msleep(1);
+       }
+       b43err(dev->wl, "RF sequence status timeout\n");
+ok:
+       b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+                    ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+}
+
+static void b43_nphy_bphy_init(struct b43_wldev *dev)
+{
+       unsigned int i;
+       u16 val;
+
+       val = 0x1E1F;
+       for (i = 0; i < 14; i++) {
+               b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+               val -= 0x202;
+       }
+       val = 0x3E3F;
+       for (i = 0; i < 16; i++) {
+               b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+               val -= 0x202;
+       }
+       b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/* RSSI Calibration */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+       //TODO
+}
+
+int b43_phy_initn(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       u16 tmp;
+
+       //TODO: Spectral management
+       b43_nphy_tables_init(dev);
+
+       /* Clear all overrides */
+       b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+       b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+                    ~(B43_NPHY_RFSEQMODE_CAOVER |
+                      B43_NPHY_RFSEQMODE_TROVER));
+       b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
+
+       tmp = (phy->rev < 2) ? 64 : 59;
+       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                       ~B43_NPHY_BPHY_CTL3_SCALE,
+                       tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+
+       b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
+       b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
+
+       b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
+       b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
+       b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
+       b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+
+       //TODO MIMO-Config
+       //TODO Update TX/RX chain
+
+       if (phy->rev < 2) {
+               b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
+               b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
+       }
+       b43_nphy_workarounds(dev);
+       b43_nphy_reset_cca(dev);
+
+       ssb_write32(dev->dev, SSB_TMSLOW,
+                   ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+       b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
+       //TODO read core1/2 clip1 thres regs
+
+       if (1 /* FIXME Band is 2.4GHz */)
+               b43_nphy_bphy_init(dev);
+       //TODO disable TX power control
+       //TODO Fix the TX power settings
+       //TODO Init periodic calibration with reason 3
+       b43_nphy_rssi_cal(dev, 2);
+       b43_nphy_rssi_cal(dev, 0);
+       b43_nphy_rssi_cal(dev, 1);
+       //TODO get TX gain
+       //TODO init superswitch
+       //TODO calibrate LO
+       //TODO idle TSSI TX pctl
+       //TODO TX power control power setup
+       //TODO table writes
+       //TODO TX power control coefficients
+       //TODO enable TX power control
+       //TODO control antenna selection
+       //TODO init radar detection
+       //TODO reset channel if changed
+
+       b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
+       return 0;
+}
diff --git a/package/b43/src/nphy.h b/package/b43/src/nphy.h
new file mode 100644 (file)
index 0000000..5d95118
--- /dev/null
@@ -0,0 +1,932 @@
+#ifndef B43_NPHY_H_
+#define B43_NPHY_H_
+
+#include "phy.h"
+
+
+/* N-PHY registers. */
+
+#define B43_NPHY_BBCFG                         B43_PHY_N(0x001) /* BB config */
+#define  B43_NPHY_BBCFG_RSTCCA                 0x4000 /* Reset CCA */
+#define  B43_NPHY_BBCFG_RSTRX                  0x8000 /* Reset RX */
+#define B43_NPHY_CHANNEL                       B43_PHY_N(0x005) /* Channel */
+#define B43_NPHY_TXERR                         B43_PHY_N(0x007) /* TX error */
+#define B43_NPHY_BANDCTL                       B43_PHY_N(0x009) /* Band control */
+#define  B43_NPHY_BANDCTL_5GHZ                 0x0001 /* Use the 5GHz band */
+#define B43_NPHY_4WI_ADDR                      B43_PHY_N(0x00B) /* Four-wire bus address */
+#define B43_NPHY_4WI_DATAHI                    B43_PHY_N(0x00C) /* Four-wire bus data high */
+#define B43_NPHY_4WI_DATALO                    B43_PHY_N(0x00D) /* Four-wire bus data low */
+#define B43_NPHY_BIST_STAT0                    B43_PHY_N(0x00E) /* Built-in self test status 0 */
+#define B43_NPHY_BIST_STAT1                    B43_PHY_N(0x00F) /* Built-in self test status 1 */
+
+#define B43_NPHY_C1_DESPWR                     B43_PHY_N(0x018) /* Core 1 desired power */
+#define B43_NPHY_C1_CCK_DESPWR                 B43_PHY_N(0x019) /* Core 1 CCK desired power */
+#define B43_NPHY_C1_BCLIPBKOFF                 B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
+#define B43_NPHY_C1_CCK_BCLIPBKOFF             B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
+#define B43_NPHY_C1_CGAINI                     B43_PHY_N(0x01C) /* Core 1 compute gain info */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF          0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT    0
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF         0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT   5
+#define  B43_NPHY_C1_CGAINI_GAINSTEP           0x1C00 /* Gain step */
+#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT     10
+#define  B43_NPHY_C1_CGAINI_CL2DETECT          0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C1_CCK_CGAINI                 B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
+#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF      0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF     0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C1_MINMAX_GAIN                        B43_PHY_N(0x01E) /* Core 1 min/max gain */
+#define  B43_NPHY_C1_MINGAIN                   0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_MINGAIN_SHIFT             0
+#define  B43_NPHY_C1_MAXGAIN                   0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_MAXGAIN_SHIFT             8
+#define B43_NPHY_C1_CCK_MINMAX_GAIN            B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
+#define  B43_NPHY_C1_CCK_MINGAIN               0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT         0
+#define  B43_NPHY_C1_CCK_MAXGAIN               0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT         8
+#define B43_NPHY_C1_INITGAIN                   B43_PHY_N(0x020) /* Core 1 initial gain code */
+#define  B43_NPHY_C1_INITGAIN_EXTLNA           0x0001 /* External LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNA              0x0006 /* LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT     1
+#define  B43_NPHY_C1_INITGAIN_HPVGA1           0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT     3
+#define  B43_NPHY_C1_INITGAIN_HPVGA2           0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT     7
+#define  B43_NPHY_C1_INITGAIN_TRRX             0x1000 /* TR RX index */
+#define  B43_NPHY_C1_INITGAIN_TRTX             0x2000 /* TR TX index */
+#define B43_NPHY_C1_CLIP1_HIGAIN               B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
+#define B43_NPHY_C1_CLIP1_MEDGAIN              B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
+#define B43_NPHY_C1_CLIP1_LOGAIN               B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
+#define B43_NPHY_C1_CLIP2_GAIN                 B43_PHY_N(0x024) /* Core 1 clip2 gain code */
+#define B43_NPHY_C1_FILTERGAIN                 B43_PHY_N(0x025) /* Core 1 filter gain */
+#define B43_NPHY_C1_LPF_QHPF_BW                        B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
+#define B43_NPHY_C1_CLIPWBTHRES                        B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2         0x003F /* Clip 2 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT   0
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1         0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT   6
+#define B43_NPHY_C1_W1THRES                    B43_PHY_N(0x028) /* Core 1 W1 threshold */
+#define B43_NPHY_C1_EDTHRES                    B43_PHY_N(0x029) /* Core 1 ED threshold */
+#define B43_NPHY_C1_SMSIGTHRES                 B43_PHY_N(0x02A) /* Core 1 small sig threshold */
+#define B43_NPHY_C1_NBCLIPTHRES                        B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
+#define B43_NPHY_C1_CLIP1THRES                 B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
+#define B43_NPHY_C1_CLIP2THRES                 B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
+
+#define B43_NPHY_C2_DESPWR                     B43_PHY_N(0x02E) /* Core 2 desired power */
+#define B43_NPHY_C2_CCK_DESPWR                 B43_PHY_N(0x02F) /* Core 2 CCK desired power */
+#define B43_NPHY_C2_BCLIPBKOFF                 B43_PHY_N(0x030) /* Core 2 barely clip backoff */
+#define B43_NPHY_C2_CCK_BCLIPBKOFF             B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
+#define B43_NPHY_C2_CGAINI                     B43_PHY_N(0x032) /* Core 2 compute gain info */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF          0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT    0
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF         0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT   5
+#define  B43_NPHY_C2_CGAINI_GAINSTEP           0x1C00 /* Gain step */
+#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT     10
+#define  B43_NPHY_C2_CGAINI_CL2DETECT          0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C2_CCK_CGAINI                 B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
+#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF      0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF     0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C2_MINMAX_GAIN                        B43_PHY_N(0x034) /* Core 2 min/max gain */
+#define  B43_NPHY_C2_MINGAIN                   0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_MINGAIN_SHIFT             0
+#define  B43_NPHY_C2_MAXGAIN                   0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_MAXGAIN_SHIFT             8
+#define B43_NPHY_C2_CCK_MINMAX_GAIN            B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
+#define  B43_NPHY_C2_CCK_MINGAIN               0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT         0
+#define  B43_NPHY_C2_CCK_MAXGAIN               0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT         8
+#define B43_NPHY_C2_INITGAIN                   B43_PHY_N(0x036) /* Core 2 initial gain code */
+#define  B43_NPHY_C2_INITGAIN_EXTLNA           0x0001 /* External LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNA              0x0006 /* LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT     1
+#define  B43_NPHY_C2_INITGAIN_HPVGA1           0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT     3
+#define  B43_NPHY_C2_INITGAIN_HPVGA2           0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT     7
+#define  B43_NPHY_C2_INITGAIN_TRRX             0x1000 /* TR RX index */
+#define  B43_NPHY_C2_INITGAIN_TRTX             0x2000 /* TR TX index */
+#define B43_NPHY_C2_CLIP1_HIGAIN               B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_C2_CLIP1_MEDGAIN              B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_C2_CLIP1_LOGAIN               B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_C2_CLIP2_GAIN                 B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_C2_FILTERGAIN                 B43_PHY_N(0x03B) /* Core 2 filter gain */
+#define B43_NPHY_C2_LPF_QHPF_BW                        B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
+#define B43_NPHY_C2_CLIPWBTHRES                        B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2         0x003F /* Clip 2 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT   0
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1         0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT   6
+#define B43_NPHY_C2_W1THRES                    B43_PHY_N(0x03E) /* Core 2 W1 threshold */
+#define B43_NPHY_C2_EDTHRES                    B43_PHY_N(0x03F) /* Core 2 ED threshold */
+#define B43_NPHY_C2_SMSIGTHRES                 B43_PHY_N(0x040) /* Core 2 small sig threshold */
+#define B43_NPHY_C2_NBCLIPTHRES                        B43_PHY_N(0x041) /* Core 2 NB clip threshold */
+#define B43_NPHY_C2_CLIP1THRES                 B43_PHY_N(0x042) /* Core 2 clip1 threshold */
+#define B43_NPHY_C2_CLIP2THRES                 B43_PHY_N(0x043) /* Core 2 clip2 threshold */
+
+#define B43_NPHY_CRS_THRES1                    B43_PHY_N(0x044) /* CRS threshold 1 */
+#define B43_NPHY_CRS_THRES2                    B43_PHY_N(0x045) /* CRS threshold 2 */
+#define B43_NPHY_CRS_THRES3                    B43_PHY_N(0x046) /* CRS threshold 3 */
+#define B43_NPHY_CRSCTL                                B43_PHY_N(0x047) /* CRS control */
+#define B43_NPHY_DCFADDR                       B43_PHY_N(0x048) /* DC filter address */
+#define B43_NPHY_RXF20_NUM0                    B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
+#define B43_NPHY_RXF20_NUM1                    B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
+#define B43_NPHY_RXF20_NUM2                    B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
+#define B43_NPHY_RXF20_DENOM0                  B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
+#define B43_NPHY_RXF20_DENOM1                  B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
+#define B43_NPHY_RXF20_NUM10                   B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
+#define B43_NPHY_RXF20_NUM11                   B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
+#define B43_NPHY_RXF20_NUM12                   B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
+#define B43_NPHY_RXF20_DENOM10                 B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
+#define B43_NPHY_RXF20_DENOM11                 B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
+#define B43_NPHY_RXF40_NUM0                    B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
+#define B43_NPHY_RXF40_NUM1                    B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
+#define B43_NPHY_RXF40_NUM2                    B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
+#define B43_NPHY_RXF40_DENOM0                  B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
+#define B43_NPHY_RXF40_DENOM1                  B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
+#define B43_NPHY_RXF40_NUM10                   B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
+#define B43_NPHY_RXF40_NUM11                   B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
+#define B43_NPHY_RXF40_NUM12                   B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
+#define B43_NPHY_RXF40_DENOM10                 B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
+#define B43_NPHY_RXF40_DENOM11                 B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
+#define B43_NPHY_PPROC_RSTLEN                  B43_PHY_N(0x060) /* Packet processing reset length */
+#define B43_NPHY_INITCARR_DLEN                 B43_PHY_N(0x061) /* Initial carrier detection length */
+#define B43_NPHY_CLIP1CARR_DLEN                        B43_PHY_N(0x062) /* Clip1 carrier detection length */
+#define B43_NPHY_CLIP2CARR_DLEN                        B43_PHY_N(0x063) /* Clip2 carrier detection length */
+#define B43_NPHY_INITGAIN_SLEN                 B43_PHY_N(0x064) /* Initial gain settle length */
+#define B43_NPHY_CLIP1GAIN_SLEN                        B43_PHY_N(0x065) /* Clip1 gain settle length */
+#define B43_NPHY_CLIP2GAIN_SLEN                        B43_PHY_N(0x066) /* Clip2 gain settle length */
+#define B43_NPHY_PACKGAIN_SLEN                 B43_PHY_N(0x067) /* Packet gain settle length */
+#define B43_NPHY_CARRSRC_TLEN                  B43_PHY_N(0x068) /* Carrier search timeout length */
+#define B43_NPHY_TISRC_TLEN                    B43_PHY_N(0x069) /* Timing search timeout length */
+#define B43_NPHY_ENDROP_TLEN                   B43_PHY_N(0x06A) /* Energy drop timeout length */
+#define B43_NPHY_CLIP1_NBDWELL_LEN             B43_PHY_N(0x06B) /* Clip1 NB dwell length */
+#define B43_NPHY_CLIP2_NBDWELL_LEN             B43_PHY_N(0x06C) /* Clip2 NB dwell length */
+#define B43_NPHY_W1CLIP1_DWELL_LEN             B43_PHY_N(0x06D) /* W1 clip1 dwell length */
+#define B43_NPHY_W1CLIP2_DWELL_LEN             B43_PHY_N(0x06E) /* W1 clip2 dwell length */
+#define B43_NPHY_W2CLIP1_DWELL_LEN             B43_PHY_N(0x06F) /* W2 clip1 dwell length */
+#define B43_NPHY_PLOAD_CSENSE_EXTLEN           B43_PHY_N(0x070) /* Payload carrier sense extension length */
+#define B43_NPHY_EDROP_CSENSE_EXTLEN           B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
+#define B43_NPHY_TABLE_ADDR                    B43_PHY_N(0x072) /* Table address */
+#define B43_NPHY_TABLE_DATALO                  B43_PHY_N(0x073) /* Table data low */
+#define B43_NPHY_TABLE_DATAHI                  B43_PHY_N(0x074) /* Table data high */
+#define B43_NPHY_WWISE_LENIDX                  B43_PHY_N(0x075) /* WWiSE length index */
+#define B43_NPHY_TGNSYNC_LENIDX                        B43_PHY_N(0x076) /* TGNsync length index */
+#define B43_NPHY_TXMACIF_HOLDOFF               B43_PHY_N(0x077) /* TX MAC IF Hold off */
+#define B43_NPHY_RFCTL_CMD                     B43_PHY_N(0x078) /* RF control (command) */
+#define  B43_NPHY_RFCTL_CMD_START              0x0001 /* Start sequence */
+#define  B43_NPHY_RFCTL_CMD_RXTX               0x0002 /* RX/TX */
+#define  B43_NPHY_RFCTL_CMD_CORESEL            0x0038 /* Core select */
+#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT      3
+#define  B43_NPHY_RFCTL_CMD_PORFORCE           0x0040 /* POR force */
+#define  B43_NPHY_RFCTL_CMD_OEPORFORCE         0x0080 /* OE POR force */
+#define  B43_NPHY_RFCTL_CMD_RXEN               0x0100 /* RX enable */
+#define  B43_NPHY_RFCTL_CMD_TXEN               0x0200 /* TX enable */
+#define  B43_NPHY_RFCTL_CMD_CHIP0PU            0x0400 /* Chip0 PU */
+#define  B43_NPHY_RFCTL_CMD_EN                 0x0800 /* Radio enabled */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE          0xF000 /* Seq en core */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT    12
+#define B43_NPHY_RFCTL_RSSIO1                  B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
+#define  B43_NPHY_RFCTL_RSSIO1_RXPD            0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_TXPD            0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_PAPD            0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL         0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO1_LPFBW           0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI         0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO                0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG1                    B43_PHY_N(0x07B) /* RF control (RX gain 1) */
+#define B43_NPHY_RFCTL_TXG1                    B43_PHY_N(0x07C) /* RF control (TX gain 1) */
+#define B43_NPHY_RFCTL_RSSIO2                  B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
+#define  B43_NPHY_RFCTL_RSSIO2_RXPD            0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_TXPD            0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_PAPD            0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL         0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO2_LPFBW           0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI         0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO                0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG2                    B43_PHY_N(0x07E) /* RF control (RX gain 2) */
+#define B43_NPHY_RFCTL_TXG2                    B43_PHY_N(0x07F) /* RF control (TX gain 2) */
+#define B43_NPHY_RFCTL_RSSIO3                  B43_PHY_N(0x080) /* RF control (RSSI others 3) */
+#define  B43_NPHY_RFCTL_RSSIO3_RXPD            0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_TXPD            0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_PAPD            0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL         0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO3_LPFBW           0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI         0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO                0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG3                    B43_PHY_N(0x081) /* RF control (RX gain 3) */
+#define B43_NPHY_RFCTL_TXG3                    B43_PHY_N(0x082) /* RF control (TX gain 3) */
+#define B43_NPHY_RFCTL_RSSIO4                  B43_PHY_N(0x083) /* RF control (RSSI others 4) */
+#define  B43_NPHY_RFCTL_RSSIO4_RXPD            0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_TXPD            0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_PAPD            0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL         0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO4_LPFBW           0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI         0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO                0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG4                    B43_PHY_N(0x084) /* RF control (RX gain 4) */
+#define B43_NPHY_RFCTL_TXG4                    B43_PHY_N(0x085) /* RF control (TX gain 4) */
+#define B43_NPHY_C1_TXIQ_COMP_OFF              B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
+#define B43_NPHY_C2_TXIQ_COMP_OFF              B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
+#define B43_NPHY_C1_TXCTL                      B43_PHY_N(0x08B) /* Core 1 TX control */
+#define B43_NPHY_C2_TXCTL                      B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_SCRAM_SIGCTL                  B43_PHY_N(0x090) /* Scram signal control */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST          0x007F /* Initial state value */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT    0
+#define  B43_NPHY_SCRAM_SIGCTL_SCM             0x0080 /* Scram control mode */
+#define  B43_NPHY_SCRAM_SIGCTL_SICE            0x0100 /* Scram index control enable */
+#define  B43_NPHY_SCRAM_SIGCTL_START           0xFE00 /* Scram start bit */
+#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT     9
+#define B43_NPHY_RFCTL_INTC1                   B43_PHY_N(0x091) /* RF control (intc 1) */
+#define B43_NPHY_RFCTL_INTC2                   B43_PHY_N(0x092) /* RF control (intc 2) */
+#define B43_NPHY_RFCTL_INTC3                   B43_PHY_N(0x093) /* RF control (intc 3) */
+#define B43_NPHY_RFCTL_INTC4                   B43_PHY_N(0x094) /* RF control (intc 4) */
+#define B43_NPHY_NRDTO_WWISE                   B43_PHY_N(0x095) /* # datatones WWiSE */
+#define B43_NPHY_NRDTO_TGNSYNC                 B43_PHY_N(0x096) /* # datatones TGNsync */
+#define B43_NPHY_SIGFMOD_WWISE                 B43_PHY_N(0x097) /* Signal field mod WWiSE */
+#define B43_NPHY_LEG_SIGFMOD_11N               B43_PHY_N(0x098) /* Legacy signal field mod 11n */
+#define B43_NPHY_HT_SIGFMOD_11N                        B43_PHY_N(0x099) /* HT signal field mod 11n */
+#define B43_NPHY_C1_RXIQ_COMPA0                        B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
+#define B43_NPHY_C1_RXIQ_COMPB0                        B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
+#define B43_NPHY_C2_RXIQ_COMPA1                        B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
+#define B43_NPHY_C2_RXIQ_COMPB1                        B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
+#define B43_NPHY_RXCTL                         B43_PHY_N(0x0A0) /* RX control */
+#define  B43_NPHY_RXCTL_BSELU20                        0x0010 /* Band select upper 20 */
+#define  B43_NPHY_RXCTL_RIFSEN                 0x0080 /* RIFS enable */
+#define B43_NPHY_RFSEQMODE                     B43_PHY_N(0x0A1) /* RF seq mode */
+#define  B43_NPHY_RFSEQMODE_CAOVER             0x0001 /* Core active override */
+#define  B43_NPHY_RFSEQMODE_TROVER             0x0002 /* Trigger override */
+#define B43_NPHY_RFSEQCA                       B43_PHY_N(0x0A2) /* RF seq core active */
+#define  B43_NPHY_RFSEQCA_TXEN                 0x000F /* TX enable */
+#define  B43_NPHY_RFSEQCA_TXEN_SHIFT           0
+#define  B43_NPHY_RFSEQCA_RXEN                 0x00F0 /* RX enable */
+#define  B43_NPHY_RFSEQCA_RXEN_SHIFT           4
+#define  B43_NPHY_RFSEQCA_TXDIS                        0x0F00 /* TX disable */
+#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT          8
+#define  B43_NPHY_RFSEQCA_RXDIS                        0xF000 /* RX disable */
+#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT          12
+#define B43_NPHY_RFSEQTR                       B43_PHY_N(0x0A3) /* RF seq trigger */
+#define  B43_NPHY_RFSEQTR_RX2TX                        0x0001 /* RX2TX */
+#define  B43_NPHY_RFSEQTR_TX2RX                        0x0002 /* TX2RX */
+#define  B43_NPHY_RFSEQTR_UPGH                 0x0004 /* Update gain H */
+#define  B43_NPHY_RFSEQTR_UPGL                 0x0008 /* Update gain L */
+#define  B43_NPHY_RFSEQTR_UPGU                 0x0010 /* Update gain U */
+#define  B43_NPHY_RFSEQTR_RST2RX               0x0020 /* Reset to RX */
+#define B43_NPHY_RFSEQST                       B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
+#define B43_NPHY_AFECTL_OVER                   B43_PHY_N(0x0A5) /* AFE control override */
+#define B43_NPHY_AFECTL_C1                     B43_PHY_N(0x0A6) /* AFE control core 1 */
+#define B43_NPHY_AFECTL_C2                     B43_PHY_N(0x0A7) /* AFE control core 2 */
+#define B43_NPHY_AFECTL_C3                     B43_PHY_N(0x0A8) /* AFE control core 3 */
+#define B43_NPHY_AFECTL_C4                     B43_PHY_N(0x0A9) /* AFE control core 4 */
+#define B43_NPHY_AFECTL_DACGAIN1               B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
+#define B43_NPHY_AFECTL_DACGAIN2               B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
+#define B43_NPHY_AFECTL_DACGAIN3               B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
+#define B43_NPHY_AFECTL_DACGAIN4               B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
+#define B43_NPHY_STR_ADDR1                     B43_PHY_N(0x0AE) /* STR address 1 */
+#define B43_NPHY_STR_ADDR2                     B43_PHY_N(0x0AF) /* STR address 2 */
+#define B43_NPHY_CLASSCTL                      B43_PHY_N(0x0B0) /* Classifier control */
+#define  B43_NPHY_CLASSCTL_CCKEN               0x0001 /* CCK enable */
+#define  B43_NPHY_CLASSCTL_OFDMEN              0x0002 /* OFDM enable */
+#define  B43_NPHY_CLASSCTL_WAITEDEN            0x0004 /* Waited enable */
+#define B43_NPHY_IQFLIP                                B43_PHY_N(0x0B1) /* I/Q flip */
+#define  B43_NPHY_IQFLIP_ADC1                  0x0001 /* ADC1 */
+#define  B43_NPHY_IQFLIP_ADC2                  0x0010 /* ADC2 */
+#define B43_NPHY_SISO_SNR_THRES                        B43_PHY_N(0x0B2) /* SISO SNR threshold */
+#define B43_NPHY_SIGMA_N_MULT                  B43_PHY_N(0x0B3) /* Sigma N multiplier */
+#define B43_NPHY_TXMACDELAY                    B43_PHY_N(0x0B4) /* TX MAC delay */
+#define B43_NPHY_TXFRAMEDELAY                  B43_PHY_N(0x0B5) /* TX frame delay */
+#define B43_NPHY_MLPARM                                B43_PHY_N(0x0B6) /* ML parameters */
+#define B43_NPHY_MLCTL                         B43_PHY_N(0x0B7) /* ML control */
+#define B43_NPHY_WWISE_20NCYCDAT               B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
+#define B43_NPHY_WWISE_40NCYCDAT               B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
+#define B43_NPHY_TGNSYNC_20NCYCDAT             B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
+#define B43_NPHY_TGNSYNC_40NCYCDAT             B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
+#define B43_NPHY_INITSWIZP                     B43_PHY_N(0x0BC) /* Initial swizzle pattern */
+#define B43_NPHY_TXTAILCNT                     B43_PHY_N(0x0BD) /* TX tail count value */
+#define B43_NPHY_BPHY_CTL1                     B43_PHY_N(0x0BE) /* B PHY control 1 */
+#define B43_NPHY_BPHY_CTL2                     B43_PHY_N(0x0BF) /* B PHY control 2 */
+#define  B43_NPHY_BPHY_CTL2_LUT                        0x001F /* LUT index */
+#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT          0
+#define  B43_NPHY_BPHY_CTL2_MACDEL             0x7FE0 /* MAC delay */
+#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT       5
+#define B43_NPHY_IQLOCAL_CMD                   B43_PHY_N(0x0C0) /* I/Q LO cal command */
+#define  B43_NPHY_IQLOCAL_CMD_EN               0x8000
+#define B43_NPHY_IQLOCAL_CMDNNUM               B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
+#define B43_NPHY_IQLOCAL_CMDGCTL               B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
+#define B43_NPHY_SAMP_CMD                      B43_PHY_N(0x0C3) /* Sample command */
+#define  B43_NPHY_SAMP_CMD_STOP                        0x0002 /* Stop */
+#define B43_NPHY_SAMP_LOOPCNT                  B43_PHY_N(0x0C4) /* Sample loop count */
+#define B43_NPHY_SAMP_WAITCNT                  B43_PHY_N(0x0C5) /* Sample wait count */
+#define B43_NPHY_SAMP_DEPCNT                   B43_PHY_N(0x0C6) /* Sample depth count */
+#define B43_NPHY_SAMP_STAT                     B43_PHY_N(0x0C7) /* Sample status */
+#define B43_NPHY_GPIO_LOOEN                    B43_PHY_N(0x0C8) /* GPIO low out enable */
+#define B43_NPHY_GPIO_HIOEN                    B43_PHY_N(0x0C9) /* GPIO high out enable */
+#define B43_NPHY_GPIO_SEL                      B43_PHY_N(0x0CA) /* GPIO select */
+#define B43_NPHY_GPIO_CLKCTL                   B43_PHY_N(0x0CB) /* GPIO clock control */
+#define B43_NPHY_TXF_20CO_AS0                  B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
+#define B43_NPHY_TXF_20CO_AS1                  B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
+#define B43_NPHY_TXF_20CO_AS2                  B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
+#define B43_NPHY_TXF_20CO_B32S0                        B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
+#define B43_NPHY_TXF_20CO_B1S0                 B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
+#define B43_NPHY_TXF_20CO_B32S1                        B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
+#define B43_NPHY_TXF_20CO_B1S1                 B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
+#define B43_NPHY_TXF_20CO_B32S2                        B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
+#define B43_NPHY_TXF_20CO_B1S2                 B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
+#define B43_NPHY_SIGFLDTOL                     B43_PHY_N(0x0D5) /* Signal fld tolerance */
+#define B43_NPHY_TXSERFLD                      B43_PHY_N(0x0D6) /* TX service field */
+#define B43_NPHY_AFESEQ_RX2TX_PUD              B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
+#define B43_NPHY_AFESEQ_TX2RX_PUD              B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
+#define B43_NPHY_TGNSYNC_SCRAMI0               B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
+#define B43_NPHY_TGNSYNC_SCRAMI1               B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
+#define B43_NPHY_INITSWIZPATTLEG               B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
+#define B43_NPHY_BPHY_CTL3                     B43_PHY_N(0x0DC) /* B PHY control 3 */
+#define  B43_NPHY_BPHY_CTL3_SCALE              0x00FF /* Scale */
+#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT                0
+#define  B43_NPHY_BPHY_CTL3_FSC                        0xFF00 /* Frame start count value */
+#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT          8
+#define B43_NPHY_BPHY_CTL4                     B43_PHY_N(0x0DD) /* B PHY control 4 */
+#define B43_NPHY_C1_TXBBMULT                   B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
+#define B43_NPHY_C2_TXBBMULT                   B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
+#define B43_NPHY_TXF_40CO_AS0                  B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
+#define B43_NPHY_TXF_40CO_AS1                  B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
+#define B43_NPHY_TXF_40CO_AS2                  B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
+#define B43_NPHY_TXF_40CO_B32S0                        B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
+#define B43_NPHY_TXF_40CO_B1S0                 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
+#define B43_NPHY_TXF_40CO_B32S1                        B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
+#define B43_NPHY_TXF_40CO_B1S1                 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
+#define B43_NPHY_TXF_40CO_B32S2                        B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
+#define B43_NPHY_TXF_40CO_B1S2                 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
+#define B43_NPHY_BIST_STAT2                    B43_PHY_N(0x0EA) /* BIST status 2 */
+#define B43_NPHY_BIST_STAT3                    B43_PHY_N(0x0EB) /* BIST status 3 */
+#define B43_NPHY_RFCTL_OVER                    B43_PHY_N(0x0EC) /* RF control override */
+#define B43_NPHY_MIMOCFG                       B43_PHY_N(0x0ED) /* MIMO config */
+#define  B43_NPHY_MIMOCFG_GFMIX                        0x0004 /* Greenfield or mixed mode */
+#define  B43_NPHY_MIMOCFG_AUTO                 0x0100 /* Greenfield/mixed mode auto */
+#define B43_NPHY_RADAR_BLNKCTL                 B43_PHY_N(0x0EE) /* Radar blank control */
+#define B43_NPHY_A0RADAR_FIFOCTL               B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
+#define B43_NPHY_A1RADAR_FIFOCTL               B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
+#define B43_NPHY_A0RADAR_FIFODAT               B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
+#define B43_NPHY_A1RADAR_FIFODAT               B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
+#define B43_NPHY_RADAR_THRES0                  B43_PHY_N(0x0F3) /* Radar threshold 0 */
+#define B43_NPHY_RADAR_THRES1                  B43_PHY_N(0x0F4) /* Radar threshold 1 */
+#define B43_NPHY_RADAR_THRES0R                 B43_PHY_N(0x0F5) /* Radar threshold 0R */
+#define B43_NPHY_RADAR_THRES1R                 B43_PHY_N(0x0F6) /* Radar threshold 1R */
+#define B43_NPHY_CSEN_20IN40_DLEN              B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO1            B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP1            B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO2            B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP2            B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO3            B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP3            B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO4            B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP4            B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
+#define B43_NPHY_RFCTL_LUT_LNAPA1              B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
+#define B43_NPHY_RFCTL_LUT_LNAPA2              B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
+#define B43_NPHY_RFCTL_LUT_LNAPA3              B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
+#define B43_NPHY_RFCTL_LUT_LNAPA4              B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
+#define B43_NPHY_TGNSYNC_CRCM0                 B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
+#define B43_NPHY_TGNSYNC_CRCM1                 B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
+#define B43_NPHY_TGNSYNC_CRCM2                 B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
+#define B43_NPHY_TGNSYNC_CRCM3                 B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
+#define B43_NPHY_TGNSYNC_CRCM4                 B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
+#define B43_NPHY_CRCPOLY                       B43_PHY_N(0x109) /* CRC polynomial */
+#define B43_NPHY_SIGCNT                                B43_PHY_N(0x10A) /* # sig count */
+#define B43_NPHY_SIGSTARTBIT_CTL               B43_PHY_N(0x10B) /* Sig start bit control */
+#define B43_NPHY_CRCPOLY_ORDER                 B43_PHY_N(0x10C) /* CRC polynomial order */
+#define B43_NPHY_RFCTL_CST0                    B43_PHY_N(0x10D) /* RF control core swap table 0 */
+#define B43_NPHY_RFCTL_CST1                    B43_PHY_N(0x10E) /* RF control core swap table 1 */
+#define B43_NPHY_RFCTL_CST2O                   B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
+#define B43_NPHY_BPHY_CTL5                     B43_PHY_N(0x111) /* B PHY control 5 */
+#define B43_NPHY_RFSEQ_LPFBW                   B43_PHY_N(0x112) /* RF seq LPF bandwidth */
+#define B43_NPHY_TSSIBIAS1                     B43_PHY_N(0x114) /* TSSI bias val 1 */
+#define B43_NPHY_TSSIBIAS2                     B43_PHY_N(0x115) /* TSSI bias val 2 */
+#define  B43_NPHY_TSSIBIAS_BIAS                        0x00FF /* Bias */
+#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT          0
+#define  B43_NPHY_TSSIBIAS_VAL                 0xFF00 /* Value */
+#define  B43_NPHY_TSSIBIAS_VAL_SHIFT           8
+#define B43_NPHY_ESTPWR1                       B43_PHY_N(0x118) /* Estimated power 1 */
+#define B43_NPHY_ESTPWR2                       B43_PHY_N(0x119) /* Estimated power 2 */
+#define  B43_NPHY_ESTPWR_PWR                   0x00FF /* Estimated power */
+#define  B43_NPHY_ESTPWR_PWR_SHIFT             0
+#define  B43_NPHY_ESTPWR_VALID                 0x0100 /* Estimated power valid */
+#define B43_NPHY_TSSI_MAXTXFDT                 B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL            0x00FF /* max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT      0
+#define B43_NPHY_TSSI_MAXTDT                   B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL              0x00FF /* max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT                0
+#define B43_NPHY_ITSSI1                                B43_PHY_N(0x11E) /* TSSI idle 1 */
+#define B43_NPHY_ITSSI2                                B43_PHY_N(0x11F) /* TSSI idle 2 */
+#define  B43_NPHY_ITSSI_VAL                    0x00FF /* Idle TSSI */
+#define  B43_NPHY_ITSSI_VAL_SHIFT              0
+#define B43_NPHY_TSSIMODE                      B43_PHY_N(0x122) /* TSSI mode */
+#define  B43_NPHY_TSSIMODE_EN                  0x0001 /* TSSI enable */
+#define  B43_NPHY_TSSIMODE_PDEN                        0x0002 /* Power det enable */
+#define B43_NPHY_RXMACIFM                      B43_PHY_N(0x123) /* RX Macif mode */
+#define B43_NPHY_CRSIT_COCNT_LO                        B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
+#define B43_NPHY_CRSIT_COCNT_HI                        B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
+#define B43_NPHY_CRSIT_MTCNT_LO                        B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
+#define B43_NPHY_CRSIT_MTCNT_HI                        B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
+#define B43_NPHY_SAMTWC                                B43_PHY_N(0x128) /* Sample tail wait count */
+#define B43_NPHY_IQEST_CMD                     B43_PHY_N(0x129) /* I/Q estimate command */
+#define  B43_NPHY_IQEST_CMD_START              0x0001 /* Start */
+#define  B43_NPHY_IQEST_CMD_MODE               0x0002 /* Mode */
+#define B43_NPHY_IQEST_WT                      B43_PHY_N(0x12A) /* I/Q estimate wait time */
+#define  B43_NPHY_IQEST_WT_VAL                 0x00FF /* Wait time */
+#define  B43_NPHY_IQEST_WT_VAL_SHIFT           0
+#define B43_NPHY_IQEST_SAMCNT                  B43_PHY_N(0x12B) /* I/Q estimate sample count */
+#define B43_NPHY_IQEST_IQACC_LO0               B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
+#define B43_NPHY_IQEST_IQACC_HI0               B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
+#define B43_NPHY_IQEST_IPACC_LO0               B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
+#define B43_NPHY_IQEST_IPACC_HI0               B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
+#define B43_NPHY_IQEST_QPACC_LO0               B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
+#define B43_NPHY_IQEST_QPACC_HI0               B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
+#define B43_NPHY_IQEST_IQACC_LO1               B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
+#define B43_NPHY_IQEST_IQACC_HI1               B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
+#define B43_NPHY_IQEST_IPACC_LO1               B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
+#define B43_NPHY_IQEST_IPACC_HI1               B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
+#define B43_NPHY_IQEST_QPACC_LO1               B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
+#define B43_NPHY_IQEST_QPACC_HI1               B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
+#define B43_NPHY_MIMO_CRSTXEXT                 B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
+#define B43_NPHY_PWRDET1                       B43_PHY_N(0x13B) /* Power det 1 */
+#define B43_NPHY_PWRDET2                       B43_PHY_N(0x13C) /* Power det 2 */
+#define B43_NPHY_MAXRSSI_DTIME                 B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
+#define B43_NPHY_PIL_DW0                       B43_PHY_N(0x141) /* Pilot data weight 0 */
+#define B43_NPHY_PIL_DW1                       B43_PHY_N(0x142) /* Pilot data weight 1 */
+#define B43_NPHY_PIL_DW2                       B43_PHY_N(0x143) /* Pilot data weight 2 */
+#define  B43_NPHY_PIL_DW_BPSK                  0x000F /* BPSK */
+#define  B43_NPHY_PIL_DW_BPSK_SHIFT            0
+#define  B43_NPHY_PIL_DW_QPSK                  0x00F0 /* QPSK */
+#define  B43_NPHY_PIL_DW_QPSK_SHIFT            4
+#define  B43_NPHY_PIL_DW_16QAM                 0x0F00 /* 16-QAM */
+#define  B43_NPHY_PIL_DW_16QAM_SHIFT           8
+#define  B43_NPHY_PIL_DW_64QAM                 0xF000 /* 64-QAM */
+#define  B43_NPHY_PIL_DW_64QAM_SHIFT           12
+#define B43_NPHY_FMDEM_CFG                     B43_PHY_N(0x144) /* FM demodulation config */
+#define B43_NPHY_PHASETR_A0                    B43_PHY_N(0x145) /* Phase track alpha 0 */
+#define B43_NPHY_PHASETR_A1                    B43_PHY_N(0x146) /* Phase track alpha 1 */
+#define B43_NPHY_PHASETR_A2                    B43_PHY_N(0x147) /* Phase track alpha 2 */
+#define B43_NPHY_PHASETR_B0                    B43_PHY_N(0x148) /* Phase track beta 0 */
+#define B43_NPHY_PHASETR_B1                    B43_PHY_N(0x149) /* Phase track beta 1 */
+#define B43_NPHY_PHASETR_B2                    B43_PHY_N(0x14A) /* Phase track beta 2 */
+#define B43_NPHY_PHASETR_CHG0                  B43_PHY_N(0x14B) /* Phase track change 0 */
+#define B43_NPHY_PHASETR_CHG1                  B43_PHY_N(0x14C) /* Phase track change 1 */
+#define B43_NPHY_PHASETW_OFF                   B43_PHY_N(0x14D) /* Phase track offset */
+#define B43_NPHY_RFCTL_DBG                     B43_PHY_N(0x14E) /* RF control debug */
+#define B43_NPHY_CCK_SHIFTB_REF                        B43_PHY_N(0x150) /* CCK shiftbits reference var */
+#define B43_NPHY_OVER_DGAIN0                   B43_PHY_N(0x152) /* Override digital gain 0 */
+#define B43_NPHY_OVER_DGAIN1                   B43_PHY_N(0x153) /* Override digital gain 1 */
+#define  B43_NPHY_OVER_DGAIN_FDGV              0x0007 /* Force digital gain value */
+#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT                0
+#define  B43_NPHY_OVER_DGAIN_FDGEN             0x0008 /* Force digital gain enable */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV          0xFF00 /* CCK digital gain enable count value */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT    8
+#define B43_NPHY_BIST_STAT4                    B43_PHY_N(0x156) /* BIST status 4 */
+#define B43_NPHY_RADAR_MAL                     B43_PHY_N(0x157) /* Radar MA length */
+#define B43_NPHY_RADAR_SRCCTL                  B43_PHY_N(0x158) /* Radar search control */
+#define B43_NPHY_VLD_DTSIG                     B43_PHY_N(0x159) /* VLD data tones sig */
+#define B43_NPHY_VLD_DTDAT                     B43_PHY_N(0x15A) /* VLD data tones data */
+#define B43_NPHY_C1_BPHY_RXIQCA0               B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
+#define B43_NPHY_C1_BPHY_RXIQCB0               B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
+#define B43_NPHY_C2_BPHY_RXIQCA1               B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
+#define B43_NPHY_C2_BPHY_RXIQCB1               B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
+#define B43_NPHY_FREQGAIN0                     B43_PHY_N(0x160) /* Frequency gain 0 */
+#define B43_NPHY_FREQGAIN1                     B43_PHY_N(0x161) /* Frequency gain 1 */
+#define B43_NPHY_FREQGAIN2                     B43_PHY_N(0x162) /* Frequency gain 2 */
+#define B43_NPHY_FREQGAIN3                     B43_PHY_N(0x163) /* Frequency gain 3 */
+#define B43_NPHY_FREQGAIN4                     B43_PHY_N(0x164) /* Frequency gain 4 */
+#define B43_NPHY_FREQGAIN5                     B43_PHY_N(0x165) /* Frequency gain 5 */
+#define B43_NPHY_FREQGAIN6                     B43_PHY_N(0x166) /* Frequency gain 6 */
+#define B43_NPHY_FREQGAIN7                     B43_PHY_N(0x167) /* Frequency gain 7 */
+#define B43_NPHY_FREQGAIN_BYPASS               B43_PHY_N(0x168) /* Frequency gain bypass */
+#define B43_NPHY_TRLOSS                                B43_PHY_N(0x169) /* TR loss value */
+#define B43_NPHY_C1_ADCCLIP                    B43_PHY_N(0x16A) /* Core 1 ADC clip */
+#define B43_NPHY_C2_ADCCLIP                    B43_PHY_N(0x16B) /* Core 2 ADC clip */
+#define B43_NPHY_LTRN_OFFGAIN                  B43_PHY_N(0x16F) /* LTRN offset gain */
+#define B43_NPHY_LTRN_OFF                      B43_PHY_N(0x170) /* LTRN offset */
+#define B43_NPHY_NRDATAT_WWISE20SIG            B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
+#define B43_NPHY_NRDATAT_WWISE40SIG            B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC20SIG          B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC40SIG          B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
+#define B43_NPHY_WWISE_CRCM0                   B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
+#define B43_NPHY_WWISE_CRCM1                   B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
+#define B43_NPHY_WWISE_CRCM2                   B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
+#define B43_NPHY_WWISE_CRCM3                   B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
+#define B43_NPHY_WWISE_CRCM4                   B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
+#define B43_NPHY_CHANEST_CDDSH                 B43_PHY_N(0x17A) /* Channel estimate CDD shift */
+#define B43_NPHY_HTAGC_WCNT                    B43_PHY_N(0x17B) /* HT ADC wait counters */
+#define B43_NPHY_SQPARM                                B43_PHY_N(0x17C) /* SQ params */
+#define B43_NPHY_MCSDUP6M                      B43_PHY_N(0x17D) /* MCS dup 6M */
+#define B43_NPHY_NDATAT_DUP40                  B43_PHY_N(0x17E) /* # data tones dup 40 */
+#define B43_NPHY_DUP40_TGNSYNC_CYCD            B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
+#define B43_NPHY_DUP40_GFBL                    B43_PHY_N(0x180) /* Dup40 GF format BL address */
+#define B43_NPHY_DUP40_BL                      B43_PHY_N(0x181) /* Dup40 format BL address */
+#define B43_NPHY_LEGDUP_FTA                    B43_PHY_N(0x182) /* Legacy dup frm table address */
+#define B43_NPHY_PACPROC_DBG                   B43_PHY_N(0x183) /* Packet processing debug */
+#define B43_NPHY_PIL_CYC1                      B43_PHY_N(0x184) /* Pilot cycle counter 1 */
+#define B43_NPHY_PIL_CYC2                      B43_PHY_N(0x185) /* Pilot cycle counter 2 */
+#define B43_NPHY_TXF_20CO_S0A1                 B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
+#define B43_NPHY_TXF_20CO_S0A2                 B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
+#define B43_NPHY_TXF_20CO_S1A1                 B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
+#define B43_NPHY_TXF_20CO_S1A2                 B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
+#define B43_NPHY_TXF_20CO_S2A1                 B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
+#define B43_NPHY_TXF_20CO_S2A2                 B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
+#define B43_NPHY_TXF_20CO_S0B1                 B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
+#define B43_NPHY_TXF_20CO_S0B2                 B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
+#define B43_NPHY_TXF_20CO_S0B3                 B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
+#define B43_NPHY_TXF_20CO_S1B1                 B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
+#define B43_NPHY_TXF_20CO_S1B2                 B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
+#define B43_NPHY_TXF_20CO_S1B3                 B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
+#define B43_NPHY_TXF_20CO_S2B1                 B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
+#define B43_NPHY_TXF_20CO_S2B2                 B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
+#define B43_NPHY_TXF_20CO_S2B3                 B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
+#define B43_NPHY_TXF_40CO_S0A1                 B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
+#define B43_NPHY_TXF_40CO_S0A2                 B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
+#define B43_NPHY_TXF_40CO_S1A1                 B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
+#define B43_NPHY_TXF_40CO_S1A2                 B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
+#define B43_NPHY_TXF_40CO_S2A1                 B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
+#define B43_NPHY_TXF_40CO_S2A2                 B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
+#define B43_NPHY_TXF_40CO_S0B1                 B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
+#define B43_NPHY_TXF_40CO_S0B2                 B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
+#define B43_NPHY_TXF_40CO_S0B3                 B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
+#define B43_NPHY_TXF_40CO_S1B1                 B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
+#define B43_NPHY_TXF_40CO_S1B2                 B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
+#define B43_NPHY_TXF_40CO_S1B3                 B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
+#define B43_NPHY_TXF_40CO_S2B1                 B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
+#define B43_NPHY_TXF_40CO_S2B2                 B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
+#define B43_NPHY_TXF_40CO_S2B3                 B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
+#define B43_NPHY_RSSIMC_0I_RSSI_X              B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
+#define B43_NPHY_RSSIMC_0I_RSSI_Y              B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
+#define B43_NPHY_RSSIMC_0I_RSSI_Z              B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
+#define B43_NPHY_RSSIMC_0I_TBD                 B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
+#define B43_NPHY_RSSIMC_0I_PWRDET              B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
+#define B43_NPHY_RSSIMC_0I_TSSI                        B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
+#define B43_NPHY_RSSIMC_0Q_RSSI_X              B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Y              B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Z              B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
+#define B43_NPHY_RSSIMC_0Q_TBD                 B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
+#define B43_NPHY_RSSIMC_0Q_PWRDET              B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
+#define B43_NPHY_RSSIMC_0Q_TSSI                        B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
+#define B43_NPHY_RSSIMC_1I_RSSI_X              B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
+#define B43_NPHY_RSSIMC_1I_RSSI_Y              B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
+#define B43_NPHY_RSSIMC_1I_RSSI_Z              B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
+#define B43_NPHY_RSSIMC_1I_TBD                 B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
+#define B43_NPHY_RSSIMC_1I_PWRDET              B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
+#define B43_NPHY_RSSIMC_1I_TSSI                        B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
+#define B43_NPHY_RSSIMC_1Q_RSSI_X              B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Y              B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Z              B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
+#define B43_NPHY_RSSIMC_1Q_TBD                 B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
+#define B43_NPHY_RSSIMC_1Q_PWRDET              B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
+#define B43_NPHY_RSSIMC_1Q_TSSI                        B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
+#define B43_NPHY_SAMC_WCNT                     B43_PHY_N(0x1BC) /* Sample collect wait counter */
+#define B43_NPHY_PTHROUGH_CNT                  B43_PHY_N(0x1BD) /* Pass-through counter */
+#define B43_NPHY_LTRN_OFF_G20L                 B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
+#define B43_NPHY_LTRN_OFF_20L                  B43_PHY_N(0x1C5) /* LTRN offset 20L */
+#define B43_NPHY_LTRN_OFF_G20U                 B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
+#define B43_NPHY_LTRN_OFF_20U                  B43_PHY_N(0x1C7) /* LTRN offset 20U */
+#define B43_NPHY_DSSSCCK_GAINSL                        B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
+#define B43_NPHY_GPIO_LOOUT                    B43_PHY_N(0x1C9) /* GPIO low out */
+#define B43_NPHY_GPIO_HIOUT                    B43_PHY_N(0x1CA) /* GPIO high out */
+#define B43_NPHY_CRS_CHECK                     B43_PHY_N(0x1CB) /* CRS check */
+#define B43_NPHY_ML_LOGSS_RAT                  B43_PHY_N(0x1CC) /* ML/logss ratio */
+#define B43_NPHY_DUPSCALE                      B43_PHY_N(0x1CD) /* Dup scale */
+#define B43_NPHY_BW1A                          B43_PHY_N(0x1CE) /* BW 1A */
+#define B43_NPHY_BW2                           B43_PHY_N(0x1CF) /* BW 2 */
+#define B43_NPHY_BW3                           B43_PHY_N(0x1D0) /* BW 3 */
+#define B43_NPHY_BW4                           B43_PHY_N(0x1D1) /* BW 4 */
+#define B43_NPHY_BW5                           B43_PHY_N(0x1D2) /* BW 5 */
+#define B43_NPHY_BW6                           B43_PHY_N(0x1D3) /* BW 6 */
+#define B43_NPHY_COALEN0                       B43_PHY_N(0x1D4) /* Coarse length 0 */
+#define B43_NPHY_COALEN1                       B43_PHY_N(0x1D5) /* Coarse length 1 */
+#define B43_NPHY_CRSTHRES_1U                   B43_PHY_N(0x1D6) /* CRS threshold 1 U */
+#define B43_NPHY_CRSTHRES_2U                   B43_PHY_N(0x1D7) /* CRS threshold 2 U */
+#define B43_NPHY_CRSTHRES_3U                   B43_PHY_N(0x1D8) /* CRS threshold 3 U */
+#define B43_NPHY_CRSCTL_U                      B43_PHY_N(0x1D9) /* CRS control U */
+#define B43_NPHY_CRSTHRES_1L                   B43_PHY_N(0x1DA) /* CRS threshold 1 L */
+#define B43_NPHY_CRSTHRES_2L                   B43_PHY_N(0x1DB) /* CRS threshold 2 L */
+#define B43_NPHY_CRSTHRES_3L                   B43_PHY_N(0x1DC) /* CRS threshold 3 L */
+#define B43_NPHY_CRSCTL_L                      B43_PHY_N(0x1DD) /* CRS control L */
+#define B43_NPHY_STRA_1U                       B43_PHY_N(0x1DE) /* STR address 1 U */
+#define B43_NPHY_STRA_2U                       B43_PHY_N(0x1DF) /* STR address 2 U */
+#define B43_NPHY_STRA_1L                       B43_PHY_N(0x1E0) /* STR address 1 L */
+#define B43_NPHY_STRA_2L                       B43_PHY_N(0x1E1) /* STR address 2 L */
+#define B43_NPHY_CRSCHECK1                     B43_PHY_N(0x1E2) /* CRS check 1 */
+#define B43_NPHY_CRSCHECK2                     B43_PHY_N(0x1E3) /* CRS check 2 */
+#define B43_NPHY_CRSCHECK3                     B43_PHY_N(0x1E4) /* CRS check 3 */
+#define B43_NPHY_JMPSTP0                       B43_PHY_N(0x1E5) /* Jump step 0 */
+#define B43_NPHY_JMPSTP1                       B43_PHY_N(0x1E6) /* Jump step 1 */
+#define B43_NPHY_TXPCTL_CMD                    B43_PHY_N(0x1E7) /* TX power control command */
+#define  B43_NPHY_TXPCTL_CMD_INIT              0x007F /* Init */
+#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT                0
+#define  B43_NPHY_TXPCTL_CMD_COEFF             0x2000 /* Power control coefficients */
+#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN          0x4000 /* Hardware TX power control enable */
+#define  B43_NPHY_TXPCTL_CMD_PCTLEN            0x8000 /* TX power control enable */
+#define B43_NPHY_TXPCTL_N                      B43_PHY_N(0x1E8) /* TX power control N num */
+#define  B43_NPHY_TXPCTL_N_TSSID               0x00FF /* N TSSI delay */
+#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT         0
+#define  B43_NPHY_TXPCTL_N_NPTIL2              0x0700 /* N PT integer log2 */
+#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT                8
+#define B43_NPHY_TXPCTL_ITSSI                  B43_PHY_N(0x1E9) /* TX power control idle TSSI */
+#define  B43_NPHY_TXPCTL_ITSSI_0               0x003F /* Idle TSSI 0 */
+#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT         0
+#define  B43_NPHY_TXPCTL_ITSSI_1               0x3F00 /* Idle TSSI 1 */
+#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT         8
+#define  B43_NPHY_TXPCTL_ITSSI_BINF            0x8000 /* Raw TSSI offset bin format */
+#define B43_NPHY_TXPCTL_TPWR                   B43_PHY_N(0x1EA) /* TX power control target power */
+#define  B43_NPHY_TXPCTL_TPWR_0                        0x00FF /* Power 0 */
+#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT          0
+#define  B43_NPHY_TXPCTL_TPWR_1                        0xFF00 /* Power 1 */
+#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT          8
+#define B43_NPHY_TXPCTL_BIDX                   B43_PHY_N(0x1EB) /* TX power control base index */
+#define  B43_NPHY_TXPCTL_BIDX_0                        0x007F /* uC base index 0 */
+#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT          0
+#define  B43_NPHY_TXPCTL_BIDX_1                        0x7F00 /* uC base index 1 */
+#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT          8
+#define  B43_NPHY_TXPCTL_BIDX_LOAD             0x8000 /* Load base index */
+#define B43_NPHY_TXPCTL_PIDX                   B43_PHY_N(0x1EC) /* TX power control power index */
+#define  B43_NPHY_TXPCTL_PIDX_0                        0x007F /* uC power index 0 */
+#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT          0
+#define  B43_NPHY_TXPCTL_PIDX_1                        0x7F00 /* uC power index 1 */
+#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT          8
+#define B43_NPHY_C1_TXPCTL_STAT                        B43_PHY_N(0x1ED) /* Core 1 TX power control status */
+#define B43_NPHY_C2_TXPCTL_STAT                        B43_PHY_N(0x1EE) /* Core 2 TX power control status */
+#define  B43_NPHY_TXPCTL_STAT_EST              0x00FF /* Estimated power */
+#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT                0
+#define  B43_NPHY_TXPCTL_STAT_BIDX             0x7F00 /* Base index */
+#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT       8
+#define  B43_NPHY_TXPCTL_STAT_ESTVALID         0x8000 /* Estimated power valid */
+#define B43_NPHY_SMALLSGS_LEN                  B43_PHY_N(0x1EF) /* Small sig gain settle length */
+#define B43_NPHY_PHYSTAT_GAIN0                 B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
+#define B43_NPHY_PHYSTAT_GAIN1                 B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
+#define B43_NPHY_PHYSTAT_FREQEST               B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
+#define B43_NPHY_PHYSTAT_ADVRET                        B43_PHY_N(0x1F3) /* PHY stats ADV retard */
+#define B43_NPHY_PHYLB_MODE                    B43_PHY_N(0x1F4) /* PHY loopback mode */
+#define B43_NPHY_TONE_MIDX20_1                 B43_PHY_N(0x1F5) /* Tone map index 20/1 */
+#define B43_NPHY_TONE_MIDX20_2                 B43_PHY_N(0x1F6) /* Tone map index 20/2 */
+#define B43_NPHY_TONE_MIDX20_3                 B43_PHY_N(0x1F7) /* Tone map index 20/3 */
+#define B43_NPHY_TONE_MIDX40_1                 B43_PHY_N(0x1F8) /* Tone map index 40/1 */
+#define B43_NPHY_TONE_MIDX40_2                 B43_PHY_N(0x1F9) /* Tone map index 40/2 */
+#define B43_NPHY_TONE_MIDX40_3                 B43_PHY_N(0x1FA) /* Tone map index 40/3 */
+#define B43_NPHY_TONE_MIDX40_4                 B43_PHY_N(0x1FB) /* Tone map index 40/4 */
+#define B43_NPHY_PILTONE_MIDX1                 B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
+#define B43_NPHY_PILTONE_MIDX2                 B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
+#define B43_NPHY_PILTONE_MIDX3                 B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
+#define B43_NPHY_TXRIFS_FRDEL                  B43_PHY_N(0x1FF) /* TX RIFS frame delay */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_40M          B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_40M          B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_20M          B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_20M          B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
+#define B43_NPHY_RX_SIGCTL                     B43_PHY_N(0x204) /* RX signal control */
+#define B43_NPHY_RXPIL_CYCNT0                  B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
+#define B43_NPHY_RXPIL_CYCNT1                  B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
+#define B43_NPHY_RXPIL_CYCNT2                  B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_10M          B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_10M          B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
+#define B43_NPHY_DSSSCCK_CRSEXTL               B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
+#define B43_NPHY_ML_LOGSS_RATSLOPE             B43_PHY_N(0x20B) /* ML/logss ratio slope */
+#define B43_NPHY_RIFS_SRCTL                    B43_PHY_N(0x20C) /* RIFS search timeout length */
+#define B43_NPHY_TXREALFD                      B43_PHY_N(0x20D) /* TX real frame delay */
+#define B43_NPHY_HPANT_SWTHRES                 B43_PHY_N(0x20E) /* High power antenna switch threshold */
+#define B43_NPHY_EDCRS_ASSTHRES0               B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
+#define B43_NPHY_EDCRS_ASSTHRES1               B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
+#define B43_NPHY_EDCRS_DEASSTHRES0             B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
+#define B43_NPHY_EDCRS_DEASSTHRES1             B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
+#define B43_NPHY_STR_WTIME20U                  B43_PHY_N(0x214) /* STR wait time 20U */
+#define B43_NPHY_STR_WTIME20L                  B43_PHY_N(0x215) /* STR wait time 20L */
+#define B43_NPHY_TONE_MIDX657M                 B43_PHY_N(0x216) /* Tone map index 657M */
+#define B43_NPHY_HTSIGTONES                    B43_PHY_N(0x217) /* HT signal tones */
+#define B43_NPHY_RSSI1                         B43_PHY_N(0x219) /* RSSI value 1 */
+#define B43_NPHY_RSSI2                         B43_PHY_N(0x21A) /* RSSI value 2 */
+#define B43_NPHY_CHAN_ESTHANG                  B43_PHY_N(0x21D) /* Channel estimate hang */
+#define B43_NPHY_FINERX2_CGC                   B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
+#define  B43_NPHY_FINERX2_CGC_DECGC            0x0008 /* Decode gated clocks */
+#define B43_NPHY_TXPCTL_INIT                   B43_PHY_N(0x222) /* TX power controll init */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1           0x00FF /* Power index init 1 */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT     0
+
+
+
+/* Broadcom 2055 radio registers */
+
+#define B2055_GEN_SPARE                        0x00 /* GEN spare */
+#define B2055_SP_PINPD                 0x02 /* SP PIN PD */
+#define B2055_C1_SP_RSSI               0x03 /* SP RSSI Core 1 */
+#define B2055_C1_SP_PDMISC             0x04 /* SP PD MISC Core 1 */
+#define B2055_C2_SP_RSSI               0x05 /* SP RSSI Core 2 */
+#define B2055_C2_SP_PDMISC             0x06 /* SP PD MISC Core 2 */
+#define B2055_C1_SP_RXGC1              0x07 /* SP RX GC1 Core 1 */
+#define B2055_C1_SP_RXGC2              0x08 /* SP RX GC2 Core 1 */
+#define B2055_C2_SP_RXGC1              0x09 /* SP RX GC1 Core 2 */
+#define B2055_C2_SP_RXGC2              0x0A /* SP RX GC2 Core 2 */
+#define B2055_C1_SP_LPFBWSEL           0x0B /* SP LPF BW select Core 1 */
+#define B2055_C2_SP_LPFBWSEL           0x0C /* SP LPF BW select Core 2 */
+#define B2055_C1_SP_TXGC1              0x0D /* SP TX GC1 Core 1 */
+#define B2055_C1_SP_TXGC2              0x0E /* SP TX GC2 Core 1 */
+#define B2055_C2_SP_TXGC1              0x0F /* SP TX GC1 Core 2 */
+#define B2055_C2_SP_TXGC2              0x10 /* SP TX GC2 Core 2 */
+#define B2055_MASTER1                  0x11 /* Master control 1 */
+#define B2055_MASTER2                  0x12 /* Master control 2 */
+#define B2055_PD_LGEN                  0x13 /* PD LGEN */
+#define B2055_PD_PLLTS                 0x14 /* PD PLL TS */
+#define B2055_C1_PD_LGBUF              0x15 /* PD Core 1 LGBUF */
+#define B2055_C1_PD_TX                 0x16 /* PD Core 1 TX */
+#define B2055_C1_PD_RXTX               0x17 /* PD Core 1 RXTX */
+#define B2055_C1_PD_RSSIMISC           0x18 /* PD Core 1 RSSI MISC */
+#define B2055_C2_PD_LGBUF              0x19 /* PD Core 2 LGBUF */
+#define B2055_C2_PD_TX                 0x1A /* PD Core 2 TX */
+#define B2055_C2_PD_RXTX               0x1B /* PD Core 2 RXTX */
+#define B2055_C2_PD_RSSIMISC           0x1C /* PD Core 2 RSSI MISC */
+#define B2055_PWRDET_LGEN              0x1D /* PWRDET LGEN */
+#define B2055_C1_PWRDET_LGBUF          0x1E /* PWRDET LGBUF Core 1 */
+#define B2055_C1_PWRDET_RXTX           0x1F /* PWRDET RXTX Core 1 */
+#define B2055_C2_PWRDET_LGBUF          0x20 /* PWRDET LGBUF Core 2 */
+#define B2055_C2_PWRDET_RXTX           0x21 /* PWRDET RXTX Core 2 */
+#define B2055_RRCCAL_CS                        0x22 /* RRCCAL Control spare */
+#define B2055_RRCCAL_NOPTSEL           0x23 /* RRCCAL N OPT SEL */
+#define B2055_CAL_MISC                 0x24 /* CAL MISC */
+#define B2055_CAL_COUT                 0x25 /* CAL Counter out */
+#define B2055_CAL_COUT2                        0x26 /* CAL Counter out 2 */
+#define B2055_CAL_CVARCTL              0x27 /* CAL CVAR Control */
+#define B2055_CAL_RVARCTL              0x28 /* CAL RVAR Control */
+#define B2055_CAL_LPOCTL               0x29 /* CAL LPO Control */
+#define B2055_CAL_TS                   0x2A /* CAL TS */
+#define B2055_CAL_RCCALRTS             0x2B /* CAL RCCAL READ TS */
+#define B2055_CAL_RCALRTS              0x2C /* CAL RCAL READ TS */
+#define B2055_PADDRV                   0x2D /* PAD driver */
+#define B2055_XOCTL1                   0x2E /* XO Control 1 */
+#define B2055_XOCTL2                   0x2F /* XO Control 2 */
+#define B2055_XOREGUL                  0x30 /* XO Regulator */
+#define B2055_XOMISC                   0x31 /* XO misc */
+#define B2055_PLL_LFC1                 0x32 /* PLL LF C1 */
+#define B2055_PLL_CALVTH               0x33 /* PLL CAL VTH */
+#define B2055_PLL_LFC2                 0x34 /* PLL LF C2 */
+#define B2055_PLL_REF                  0x35 /* PLL reference */
+#define B2055_PLL_LFR1                 0x36 /* PLL LF R1 */
+#define B2055_PLL_PFDCP                        0x37 /* PLL PFD CP */
+#define B2055_PLL_IDAC_CPOPAMP         0x38 /* PLL IDAC CPOPAMP */
+#define B2055_PLL_CPREG                        0x39 /* PLL CP Regulator */
+#define B2055_PLL_RCAL                 0x3A /* PLL RCAL */
+#define B2055_RF_PLLMOD0               0x3B /* RF PLL MOD0 */
+#define B2055_RF_PLLMOD1               0x3C /* RF PLL MOD1 */
+#define B2055_RF_MMDIDAC1              0x3D /* RF MMD IDAC 1 */
+#define B2055_RF_MMDIDAC0              0x3E /* RF MMD IDAC 0 */
+#define B2055_RF_MMDSP                 0x3F /* RF MMD spare */
+#define B2055_VCO_CAL1                 0x40 /* VCO cal 1 */
+#define B2055_VCO_CAL2                 0x41 /* VCO cal 2 */
+#define B2055_VCO_CAL3                 0x42 /* VCO cal 3 */
+#define B2055_VCO_CAL4                 0x43 /* VCO cal 4 */
+#define B2055_VCO_CAL5                 0x44 /* VCO cal 5 */
+#define B2055_VCO_CAL6                 0x45 /* VCO cal 6 */
+#define B2055_VCO_CAL7                 0x46 /* VCO cal 7 */
+#define B2055_VCO_CAL8                 0x47 /* VCO cal 8 */
+#define B2055_VCO_CAL9                 0x48 /* VCO cal 9 */
+#define B2055_VCO_CAL10                        0x49 /* VCO cal 10 */
+#define B2055_VCO_CAL11                        0x4A /* VCO cal 11 */
+#define B2055_VCO_CAL12                        0x4B /* VCO cal 12 */
+#define B2055_VCO_CAL13                        0x4C /* VCO cal 13 */
+#define B2055_VCO_CAL14                        0x4D /* VCO cal 14 */
+#define B2055_VCO_CAL15                        0x4E /* VCO cal 15 */
+#define B2055_VCO_CAL16                        0x4F /* VCO cal 16 */
+#define B2055_VCO_KVCO                 0x50 /* VCO KVCO */
+#define B2055_VCO_CAPTAIL              0x51 /* VCO CAP TAIL */
+#define B2055_VCO_IDACVCO              0x52 /* VCO IDAC VCO */
+#define B2055_VCO_REG                  0x53 /* VCO Regulator */
+#define B2055_PLL_RFVTH                        0x54 /* PLL RF VTH */
+#define B2055_LGBUF_CENBUF             0x55 /* LGBUF CEN BUF */
+#define B2055_LGEN_TUNE1               0x56 /* LGEN tune 1 */
+#define B2055_LGEN_TUNE2               0x57 /* LGEN tune 2 */
+#define B2055_LGEN_IDAC1               0x58 /* LGEN IDAC 1 */
+#define B2055_LGEN_IDAC2               0x59 /* LGEN IDAC 2 */
+#define B2055_LGEN_BIASC               0x5A /* LGEN BIAS counter */
+#define B2055_LGEN_BIASIDAC            0x5B /* LGEN BIAS IDAC */
+#define B2055_LGEN_RCAL                        0x5C /* LGEN RCAL */
+#define B2055_LGEN_DIV                 0x5D /* LGEN div */
+#define B2055_LGEN_SPARE2              0x5E /* LGEN spare 2 */
+#define B2055_C1_LGBUF_ATUNE           0x5F /* Core 1 LGBUF A tune */
+#define B2055_C1_LGBUF_GTUNE           0x60 /* Core 1 LGBUF G tune */
+#define B2055_C1_LGBUF_DIV             0x61 /* Core 1 LGBUF div */
+#define B2055_C1_LGBUF_AIDAC           0x62 /* Core 1 LGBUF A IDAC */
+#define B2055_C1_LGBUF_GIDAC           0x63 /* Core 1 LGBUF G IDAC */
+#define B2055_C1_LGBUF_IDACFO          0x64 /* Core 1 LGBUF IDAC filter override */
+#define B2055_C1_LGBUF_SPARE           0x65 /* Core 1 LGBUF spare */
+#define B2055_C1_RX_RFSPC1             0x66 /* Core 1 RX RF SPC1 */
+#define B2055_C1_RX_RFR1               0x67 /* Core 1 RX RF reg 1 */
+#define B2055_C1_RX_RFR2               0x68 /* Core 1 RX RF reg 2 */
+#define B2055_C1_RX_RFRCAL             0x69 /* Core 1 RX RF RCAL */
+#define B2055_C1_RX_BB_BLCMP           0x6A /* Core 1 RX Baseband BUFI LPF CMP */
+#define B2055_C1_RX_BB_LPF             0x6B /* Core 1 RX Baseband LPF */
+#define B2055_C1_RX_BB_MIDACHP         0x6C /* Core 1 RX Baseband MIDAC High-pass */
+#define B2055_C1_RX_BB_VGA1IDAC                0x6D /* Core 1 RX Baseband VGA1 IDAC */
+#define B2055_C1_RX_BB_VGA2IDAC                0x6E /* Core 1 RX Baseband VGA2 IDAC */
+#define B2055_C1_RX_BB_VGA3IDAC                0x6F /* Core 1 RX Baseband VGA3 IDAC */
+#define B2055_C1_RX_BB_BUFOCTL         0x70 /* Core 1 RX Baseband BUFO Control */
+#define B2055_C1_RX_BB_RCCALCTL                0x71 /* Core 1 RX Baseband RCCAL Control */
+#define B2055_C1_RX_BB_RSSICTL1                0x72 /* Core 1 RX Baseband RSSI Control 1 */
+#define B2055_C1_RX_BB_RSSICTL2                0x73 /* Core 1 RX Baseband RSSI Control 2 */
+#define B2055_C1_RX_BB_RSSICTL3                0x74 /* Core 1 RX Baseband RSSI Control 3 */
+#define B2055_C1_RX_BB_RSSICTL4                0x75 /* Core 1 RX Baseband RSSI Control 4 */
+#define B2055_C1_RX_BB_RSSICTL5                0x76 /* Core 1 RX Baseband RSSI Control 5 */
+#define B2055_C1_RX_BB_REG             0x77 /* Core 1 RX Baseband Regulator */
+#define B2055_C1_RX_BB_SPARE1          0x78 /* Core 1 RX Baseband spare 1 */
+#define B2055_C1_RX_TXBBRCAL           0x79 /* Core 1 RX TX BB RCAL */
+#define B2055_C1_TX_RF_SPGA            0x7A /* Core 1 TX RF SGM PGA */
+#define B2055_C1_TX_RF_SPAD            0x7B /* Core 1 TX RF SGM PAD */
+#define B2055_C1_TX_RF_CNTPGA1         0x7C /* Core 1 TX RF counter PGA 1 */
+#define B2055_C1_TX_RF_CNTPAD1         0x7D /* Core 1 TX RF counter PAD 1 */
+#define B2055_C1_TX_RF_PGAIDAC         0x7E /* Core 1 TX RF PGA IDAC */
+#define B2055_C1_TX_PGAPADTN           0x7F /* Core 1 TX PGA PAD TN */
+#define B2055_C1_TX_PADIDAC1           0x80 /* Core 1 TX PAD IDAC 1 */
+#define B2055_C1_TX_PADIDAC2           0x81 /* Core 1 TX PAD IDAC 2 */
+#define B2055_C1_TX_MXBGTRIM           0x82 /* Core 1 TX MX B/G TRIM */
+#define B2055_C1_TX_RF_RCAL            0x83 /* Core 1 TX RF RCAL */
+#define B2055_C1_TX_RF_PADTSSI1                0x84 /* Core 1 TX RF PAD TSSI1 */
+#define B2055_C1_TX_RF_PADTSSI2                0x85 /* Core 1 TX RF PAD TSSI2 */
+#define B2055_C1_TX_RF_SPARE           0x86 /* Core 1 TX RF spare */
+#define B2055_C1_TX_RF_IQCAL1          0x87 /* Core 1 TX RF I/Q CAL 1 */
+#define B2055_C1_TX_RF_IQCAL2          0x88 /* Core 1 TX RF I/Q CAL 2 */
+#define B2055_C1_TXBB_RCCAL            0x89 /* Core 1 TXBB RC CAL Control */
+#define B2055_C1_TXBB_LPF1             0x8A /* Core 1 TXBB LPF 1 */
+#define B2055_C1_TX_VOSCNCL            0x8B /* Core 1 TX VOS CNCL */
+#define B2055_C1_TX_LPF_MXGMIDAC       0x8C /* Core 1 TX LPF MXGM IDAC */
+#define B2055_C1_TX_BB_MXGM            0x8D /* Core 1 TX BB MXGM */
+#define B2055_C2_LGBUF_ATUNE           0x8E /* Core 2 LGBUF A tune */
+#define B2055_C2_LGBUF_GTUNE           0x8F /* Core 2 LGBUF G tune */
+#define B2055_C2_LGBUF_DIV             0x90 /* Core 2 LGBUF div */
+#define B2055_C2_LGBUF_AIDAC           0x91 /* Core 2 LGBUF A IDAC */
+#define B2055_C2_LGBUF_GIDAC           0x92 /* Core 2 LGBUF G IDAC */
+#define B2055_C2_LGBUF_IDACFO          0x93 /* Core 2 LGBUF IDAC filter override */
+#define B2055_C2_LGBUF_SPARE           0x94 /* Core 2 LGBUF spare */
+#define B2055_C2_RX_RFSPC1             0x95 /* Core 2 RX RF SPC1 */
+#define B2055_C2_RX_RFR1               0x96 /* Core 2 RX RF reg 1 */
+#define B2055_C2_RX_RFR2               0x97 /* Core 2 RX RF reg 2 */
+#define B2055_C2_RX_RFRCAL             0x98 /* Core 2 RX RF RCAL */
+#define B2055_C2_RX_BB_BLCMP           0x99 /* Core 2 RX Baseband BUFI LPF CMP */
+#define B2055_C2_RX_BB_LPF             0x9A /* Core 2 RX Baseband LPF */
+#define B2055_C2_RX_BB_MIDACHP         0x9B /* Core 2 RX Baseband MIDAC High-pass */
+#define B2055_C2_RX_BB_VGA1IDAC                0x9C /* Core 2 RX Baseband VGA1 IDAC */
+#define B2055_C2_RX_BB_VGA2IDAC                0x9D /* Core 2 RX Baseband VGA2 IDAC */
+#define B2055_C2_RX_BB_VGA3IDAC                0x9E /* Core 2 RX Baseband VGA3 IDAC */
+#define B2055_C2_RX_BB_BUFOCTL         0x9F /* Core 2 RX Baseband BUFO Control */
+#define B2055_C2_RX_BB_RCCALCTL                0xA0 /* Core 2 RX Baseband RCCAL Control */
+#define B2055_C2_RX_BB_RSSICTL1                0xA1 /* Core 2 RX Baseband RSSI Control 1 */
+#define B2055_C2_RX_BB_RSSICTL2                0xA2 /* Core 2 RX Baseband RSSI Control 2 */
+#define B2055_C2_RX_BB_RSSICTL3                0xA3 /* Core 2 RX Baseband RSSI Control 3 */
+#define B2055_C2_RX_BB_RSSICTL4                0xA4 /* Core 2 RX Baseband RSSI Control 4 */
+#define B2055_C2_RX_BB_RSSICTL5                0xA5 /* Core 2 RX Baseband RSSI Control 5 */
+#define B2055_C2_RX_BB_REG             0xA6 /* Core 2 RX Baseband Regulator */
+#define B2055_C2_RX_BB_SPARE1          0xA7 /* Core 2 RX Baseband spare 1 */
+#define B2055_C2_RX_TXBBRCAL           0xA8 /* Core 2 RX TX BB RCAL */
+#define B2055_C2_TX_RF_SPGA            0xA9 /* Core 2 TX RF SGM PGA */
+#define B2055_C2_TX_RF_SPAD            0xAA /* Core 2 TX RF SGM PAD */
+#define B2055_C2_TX_RF_CNTPGA1         0xAB /* Core 2 TX RF counter PGA 1 */
+#define B2055_C2_TX_RF_CNTPAD1         0xAC /* Core 2 TX RF counter PAD 1 */
+#define B2055_C2_TX_RF_PGAIDAC         0xAD /* Core 2 TX RF PGA IDAC */
+#define B2055_C2_TX_PGAPADTN           0xAE /* Core 2 TX PGA PAD TN */
+#define B2055_C2_TX_PADIDAC1           0xAF /* Core 2 TX PAD IDAC 1 */
+#define B2055_C2_TX_PADIDAC2           0xB0 /* Core 2 TX PAD IDAC 2 */
+#define B2055_C2_TX_MXBGTRIM           0xB1 /* Core 2 TX MX B/G TRIM */
+#define B2055_C2_TX_RF_RCAL            0xB2 /* Core 2 TX RF RCAL */
+#define B2055_C2_TX_RF_PADTSSI1                0xB3 /* Core 2 TX RF PAD TSSI1 */
+#define B2055_C2_TX_RF_PADTSSI2                0xB4 /* Core 2 TX RF PAD TSSI2 */
+#define B2055_C2_TX_RF_SPARE           0xB5 /* Core 2 TX RF spare */
+#define B2055_C2_TX_RF_IQCAL1          0xB6 /* Core 2 TX RF I/Q CAL 1 */
+#define B2055_C2_TX_RF_IQCAL2          0xB7 /* Core 2 TX RF I/Q CAL 2 */
+#define B2055_C2_TXBB_RCCAL            0xB8 /* Core 2 TXBB RC CAL Control */
+#define B2055_C2_TXBB_LPF1             0xB9 /* Core 2 TXBB LPF 1 */
+#define B2055_C2_TX_VOSCNCL            0xBA /* Core 2 TX VOS CNCL */
+#define B2055_C2_TX_LPF_MXGMIDAC       0xBB /* Core 2 TX LPF MXGM IDAC */
+#define B2055_C2_TX_BB_MXGM            0xBC /* Core 2 TX BB MXGM */
+#define B2055_PRG_GCHP21               0xBD /* PRG GC HPVGA23 21 */
+#define B2055_PRG_GCHP22               0xBE /* PRG GC HPVGA23 22 */
+#define B2055_PRG_GCHP23               0xBF /* PRG GC HPVGA23 23 */
+#define B2055_PRG_GCHP24               0xC0 /* PRG GC HPVGA23 24 */
+#define B2055_PRG_GCHP25               0xC1 /* PRG GC HPVGA23 25 */
+#define B2055_PRG_GCHP26               0xC2 /* PRG GC HPVGA23 26 */
+#define B2055_PRG_GCHP27               0xC3 /* PRG GC HPVGA23 27 */
+#define B2055_PRG_GCHP28               0xC4 /* PRG GC HPVGA23 28 */
+#define B2055_PRG_GCHP29               0xC5 /* PRG GC HPVGA23 29 */
+#define B2055_PRG_GCHP30               0xC6 /* PRG GC HPVGA23 30 */
+#define B2055_C1_LNA_GAINBST           0xCD /* Core 1 LNA GAINBST */
+#define B2055_C1_B0NB_RSSIVCM          0xD2 /* Core 1 B0 narrow-band RSSI VCM */
+#define B2055_C1_GENSPARE2             0xD6 /* Core 1 GEN spare 2 */
+#define B2055_C2_LNA_GAINBST           0xD9 /* Core 2 LNA GAINBST */
+#define B2055_C2_B0NB_RSSIVCM          0xDE /* Core 2 B0 narrow-band RSSI VCM */
+#define B2055_C2_GENSPARE2             0xE2 /* Core 2 GEN spare 2 */
+
+
+
+struct b43_wldev;
+
+int b43_phy_initn(struct b43_wldev *dev);
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev);
+void b43_nphy_radio_turn_off(struct b43_wldev *dev);
+
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
+
+void b43_nphy_xmitpower(struct b43_wldev *dev);
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
+
+#endif /* B43_NPHY_H_ */
index b242a9a90dd2309d0f0f8b95de5dd64ab1c6e015..b79a6bd5396d8a050d3f69f4fe8a215e0376825c 100644 (file)
@@ -65,12 +65,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        tuple_t tuple;
        cisparse_t parse;
        int err = -ENOMEM;
-       int res;
+       int res = 0;
        unsigned char buf[64];
 
        ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
        if (!ssb)
-               goto out;
+               goto out_error;
 
        err = -ENODEV;
        tuple.DesiredTuple = CISTPL_CONFIG;
@@ -96,10 +96,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        dev->io.NumPorts2 = 0;
        dev->io.Attributes2 = 0;
 
-       win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+       win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
+                        WIN_ENABLE | WIN_DATA_WIDTH_16 |
+                        WIN_USE_WAIT;
        win.Base = 0;
        win.Size = SSB_CORE_SIZE;
-       win.AccessSpeed = 1000;
+       win.AccessSpeed = 250;
        res = pcmcia_request_window(&dev, &win, &dev->win);
        if (res != CS_SUCCESS)
                goto err_kfree_ssb;
@@ -108,21 +110,34 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        mem.Page = 0;
        res = pcmcia_map_mem_page(dev->win, &mem);
        if (res != CS_SUCCESS)
-               goto err_kfree_ssb;
+               goto err_disable;
+
+       dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
+       dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
+       dev->irq.Handler = NULL; /* The handler is registered later. */
+       dev->irq.Instance = NULL;
+       res = pcmcia_request_irq(dev, &dev->irq);
+       if (res != CS_SUCCESS)
+               goto err_disable;
 
        res = pcmcia_request_configuration(dev, &dev->conf);
        if (res != CS_SUCCESS)
                goto err_disable;
 
        err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+       if (err)
+               goto err_disable;
        dev->priv = ssb;
 
-      out:
-       return err;
-      err_disable:
+       return 0;
+
+err_disable:
        pcmcia_disable_device(dev);
-      err_kfree_ssb:
+err_kfree_ssb:
        kfree(ssb);
+out_error:
+       printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
+              res, err);
        return err;
 }
 
@@ -131,22 +146,21 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
        struct ssb_bus *ssb = dev->priv;
 
        ssb_bus_unregister(ssb);
-       pcmcia_release_window(dev->win);
        pcmcia_disable_device(dev);
        kfree(ssb);
        dev->priv = NULL;
 }
 
 static struct pcmcia_driver b43_pcmcia_driver = {
-       .owner = THIS_MODULE,
-       .drv = {
-               .name = "b43-pcmcia",
-               },
-       .id_table = b43_pcmcia_tbl,
-       .probe = b43_pcmcia_probe,
-       .remove = b43_pcmcia_remove,
-       .suspend = b43_pcmcia_suspend,
-       .resume = b43_pcmcia_resume,
+       .owner          = THIS_MODULE,
+       .drv            = {
+                               .name = "b43-pcmcia",
+                       },
+       .id_table       = b43_pcmcia_tbl,
+       .probe          = b43_pcmcia_probe,
+       .remove         = __devexit_p(b43_pcmcia_remove),
+       .suspend        = b43_pcmcia_suspend,
+       .resume         = b43_pcmcia_resume,
 };
 
 int b43_pcmcia_init(void)
index 3d4ed647c311de9ebb84bc5b6b97c6af281f526e..71507b260b6d2fd5e1befb0eddee486db109034e 100644 (file)
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 
 #include "b43.h"
 #include "phy.h"
+#include "nphy.h"
 #include "main.h"
 #include "tables.h"
 #include "lo.h"
+#include "wa.h"
+
 
 static const s8 b43_tssi2dbm_b_table[] = {
        0x4D, 0x4C, 0x4B, 0x4A,
@@ -225,42 +228,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev)
        }
 }
 
-void b43_raw_phy_lock(struct b43_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43_phy_lock(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
-
-       B43_WARN_ON(!irqs_disabled());
-
-       /* We had a check for MACCTL==0 here, but I think that doesn't
-        * make sense, as MACCTL is never 0 when this is called.
-        *      --mb */
-       B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+#if B43_DEBUG
+       B43_WARN_ON(dev->phy.phy_locked);
+       dev->phy.phy_locked = 1;
+#endif
+       B43_WARN_ON(dev->dev->id.revision < 3);
 
-       if (dev->dev->id.revision < 3) {
-               b43_mac_suspend(dev);
-               spin_lock(&phy->lock);
-       } else {
-               if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-                       b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
-       }
-       phy->locked = 1;
+       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+               b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
 }
 
-void b43_raw_phy_unlock(struct b43_wldev *dev)
+void b43_phy_unlock(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
+#if B43_DEBUG
+       B43_WARN_ON(!dev->phy.phy_locked);
+       dev->phy.phy_locked = 0;
+#endif
+       B43_WARN_ON(dev->dev->id.revision < 3);
 
-       B43_WARN_ON(!irqs_disabled());
-       if (dev->dev->id.revision < 3) {
-               if (phy->locked) {
-                       spin_unlock(&phy->lock);
-                       b43_mac_enable(dev);
-               }
-       } else {
-               if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-                       b43_power_saving_ctl_bits(dev, 0);
-       }
-       phy->locked = 0;
+       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+               b43_power_saving_ctl_bits(dev, 0);
 }
 
 /* Different PHYs require different register routing flags.
@@ -271,15 +262,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
 {
        if (phy->type == B43_PHYTYPE_A) {
                /* OFDM registers are base-registers for the A-PHY. */
-               offset &= ~B43_PHYROUTE_OFDM_GPHY;
+               if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+                       offset &= ~B43_PHYROUTE;
+                       offset |= B43_PHYROUTE_BASE;
+               }
        }
-       if (offset & B43_PHYROUTE_EXT_GPHY) {
+
+#if B43_DEBUG
+       if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
                /* Ext-G registers are only available on G-PHYs */
                if (phy->type != B43_PHYTYPE_G) {
-                       b43dbg(dev->wl, "EXT-G PHY access at "
-                              "0x%04X on %u type PHY\n", offset, phy->type);
+                       b43err(dev->wl, "Invalid EXT-G PHY access at "
+                              "0x%04X on PHY type %u\n", offset, phy->type);
+                       dump_stack();
                }
        }
+       if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
+               /* N-BMODE registers are only available on N-PHYs */
+               if (phy->type != B43_PHYTYPE_N) {
+                       b43err(dev->wl, "Invalid N-BMODE PHY access at "
+                              "0x%04X on PHY type %u\n", offset, phy->type);
+                       dump_stack();
+               }
+       }
+#endif /* B43_DEBUG */
 
        return offset;
 }
@@ -299,11 +305,26 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
 
        offset = adjust_phyreg_for_phytype(phy, offset, dev);
        b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_PHY_DATA, val);
 }
 
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+       b43_phy_write(dev, offset,
+                     b43_phy_read(dev, offset) & mask);
+}
+
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+       b43_phy_write(dev, offset,
+                     b43_phy_read(dev, offset) | set);
+}
+
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+       b43_phy_write(dev, offset,
+                     (b43_phy_read(dev, offset) & mask) | set);
+}
 
 /* Adjust the transmission power output (G-PHY) */
 void b43_set_txpower_g(struct b43_wldev *dev,
@@ -763,366 +784,96 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
        b43_shm_clear_tssi(dev);
 }
 
-static void b43_phy_agcsetup(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 offset = 0x0000;
-
-       if (phy->rev == 1)
-               offset = 0x4C00;
-
-       b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
-       b43_ofdmtab_write16(dev, offset, 1, 0x000D);
-       b43_ofdmtab_write16(dev, offset, 2, 0x0013);
-       b43_ofdmtab_write16(dev, offset, 3, 0x0019);
-
-       if (phy->rev == 1) {
-               b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
-               b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
-               b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
-               b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
-               b43_phy_write(dev, 0x0455, 0x0004);
-       }
-
-       b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
-                                   & 0x00FF) | 0x5700);
-       b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-                                   & 0xFF80) | 0x000F);
-       b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-                                   & 0xC07F) | 0x2B80);
-       b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-                                   & 0xF0FF) | 0x0300);
-
-       b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
-                         | 0x0008);
-
-       b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-                                   & 0xFFF0) | 0x0008);
-       b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-                                   & 0xF0FF) | 0x0600);
-       b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-                                   & 0xF0FF) | 0x0700);
-       b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-                                   & 0xF0FF) | 0x0100);
-
-       if (phy->rev == 1) {
-               b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-                                           & 0xFFF0) | 0x0007);
-       }
-
-       b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-                                   & 0xFF00) | 0x001C);
-       b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-                                   & 0xC0FF) | 0x0200);
-       b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-                                   & 0xFF00) | 0x001C);
-       b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-                                   & 0xFF00) | 0x0020);
-       b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-                                   & 0xC0FF) | 0x0200);
-       b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
-                                   & 0xFF00) | 0x002E);
-       b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-                                   & 0x00FF) | 0x1A00);
-       b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-                                   & 0xFF00) | 0x0028);
-       b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-                                   & 0x00FF) | 0x2C00);
-
-       if (phy->rev == 1) {
-               b43_phy_write(dev, 0x0430, 0x092B);
-               b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
-                                           & 0xFFE1) | 0x0002);
-       } else {
-               b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
-                             & 0xFFE1);
-               b43_phy_write(dev, 0x041F, 0x287A);
-               b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-                                           & 0xFFF0) | 0x0004);
-       }
-
-       if (phy->rev >= 6) {
-               b43_phy_write(dev, 0x0422, 0x287A);
-               b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-                                           & 0x0FFF) | 0x3000);
-       }
-
-       b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-                                   & 0x8080) | 0x7874);
-       b43_phy_write(dev, 0x048E, 0x1C00);
-
-       offset = 0x0800;
-       if (phy->rev == 1) {
-               offset = 0x5400;
-               b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-                                           & 0xF0FF) | 0x0600);
-               b43_phy_write(dev, 0x048B, 0x005E);
-               b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-                                           & 0xFF00) | 0x001E);
-               b43_phy_write(dev, 0x048D, 0x0002);
-       }
-       b43_ofdmtab_write16(dev, offset, 0, 0x00);
-       b43_ofdmtab_write16(dev, offset, 1, 0x07);
-       b43_ofdmtab_write16(dev, offset, 2, 0x10);
-       b43_ofdmtab_write16(dev, offset, 3, 0x1C);
-
-       if (phy->rev >= 6) {
-               b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-                             & 0xFFFC);
-               b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-                             & 0xEFFF);
-       }
-}
-
-static void b43_phy_setupg(struct b43_wldev *dev)
+static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
 {
-       struct ssb_bus *bus = dev->dev->bus;
-       struct b43_phy *phy = &dev->phy;
-       u16 i;
-
-       B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-       if (phy->rev == 1) {
-               b43_phy_write(dev, 0x0406, 0x4F19);
-               b43_phy_write(dev, B43_PHY_G_CRS,
-                             (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
-                             0x0340);
-               b43_phy_write(dev, 0x042C, 0x005A);
-               b43_phy_write(dev, 0x0427, 0x001A);
-
-               for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x5800, i,
-                                           b43_tab_finefreqg[i]);
-               for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
-               for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
-       } else {
-               /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
-               b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
-
-               if (phy->rev == 2) {
-                       b43_phy_write(dev, 0x04C0, 0x1861);
-                       b43_phy_write(dev, 0x04C1, 0x0271);
-               } else if (phy->rev > 2) {
-                       b43_phy_write(dev, 0x04C0, 0x0098);
-                       b43_phy_write(dev, 0x04C1, 0x0070);
-                       b43_phy_write(dev, 0x04C9, 0x0080);
-               }
-               b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
-
-               for (i = 0; i < 64; i++)
-                       b43_ofdmtab_write16(dev, 0x4000, i, i);
-               for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
-       }
-
-       if (phy->rev <= 2)
-               for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1400, i,
-                                           b43_tab_noisescaleg1[i]);
-       else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
-               for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1400, i,
-                                           b43_tab_noisescaleg3[i]);
-       else
-               for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1400, i,
-                                           b43_tab_noisescaleg2[i]);
-
-       if (phy->rev == 2)
-               for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x5000, i,
-                                           b43_tab_sigmasqr1[i]);
-       else if ((phy->rev > 2) && (phy->rev <= 8))
-               for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x5000, i,
-                                           b43_tab_sigmasqr2[i]);
-
-       if (phy->rev == 1) {
-               for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-                       b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-               for (i = 4; i < 20; i++)
-                       b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
-               b43_phy_agcsetup(dev);
-
-               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-                   (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-                   (bus->boardinfo.rev == 0x17))
-                       return;
-
-               b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
-               b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
-       } else {
-               for (i = 0; i < 0x20; i++)
-                       b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
-               b43_phy_agcsetup(dev);
-               b43_phy_read(dev, 0x0400);      /* dummy read */
-               b43_phy_write(dev, 0x0403, 0x1000);
-               b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-               b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-
-               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-                   (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-                   (bus->boardinfo.rev == 0x17))
-                       return;
-
-               b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
-               b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
-       }
-}
-
-/* Initialize the noisescaletable for APHY */
-static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
        int i;
 
-       for (i = 0; i < 12; i++) {
-               if (phy->rev == 2)
-                       b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+       if (dev->phy.rev < 3) {
+               if (enable)
+                       for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_WRSSI, i, 0xFFF8);
+                       }
                else
-                       b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
-       }
-       if (phy->rev == 2)
-               b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
-       else
-               b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
-       for (i = 0; i < 11; i++) {
-               if (phy->rev == 2)
-                       b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+                       for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
+                       }
+       } else {
+               if (enable)
+                       for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_WRSSI, i, 0x0820);
                else
-                       b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+                       for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
+                               b43_ofdmtab_write16(dev,
+                                       B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
        }
-       if (phy->rev == 2)
-               b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
-       else
-               b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
 }
 
-static void b43_phy_setupa(struct b43_wldev *dev)
+static void b43_phy_ww(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
-       u16 i;
-
-       B43_WARN_ON(phy->type != B43_PHYTYPE_A);
-       switch (phy->rev) {
-       case 2:
-               b43_phy_write(dev, 0x008E, 0x3800);
-               b43_phy_write(dev, 0x0035, 0x03FF);
-               b43_phy_write(dev, 0x0036, 0x0400);
-
-               b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-               b43_phy_write(dev, 0x001C, 0x0FF9);
-               b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-               b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
-               b43_radio_write16(dev, 0x0002, 0x07BF);
-
-               b43_phy_write(dev, 0x0024, 0x4680);
-               b43_phy_write(dev, 0x0020, 0x0003);
-               b43_phy_write(dev, 0x001D, 0x0F40);
-               b43_phy_write(dev, 0x001F, 0x1C00);
-
-               b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-                                           & 0x00FF) | 0x0400);
-               b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
-                             & 0xFBFF);
-               b43_phy_write(dev, 0x008E, 0x58C1);
-
-               b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-               b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-               b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-               b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-               b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-               b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
-               b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
-               b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
-
-               b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-               b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-               b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
-
-               for (i = 0; i < 16; i++)
-                       b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
-
-               b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
-               b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
-               b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
-               b43_ofdmtab_write16(dev, 0x3001, 0,
-                                   (b43_ofdmtab_read16(dev, 0x3001, 0) &
-                                    0x0010) | 0x0008);
-
-               for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x5800, i,
-                                           b43_tab_finefreqa[i]);
-               for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
-                       b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
-               for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-                       b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
-               b43_phy_init_noisescaletbl(dev);
-               for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-                       b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-               break;
-       case 3:
-               for (i = 0; i < 64; i++)
-                       b43_ofdmtab_write16(dev, 0x4000, i, i);
-
-               b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-               b43_phy_write(dev, 0x001C, 0x0FF9);
-               b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-               b43_radio_write16(dev, 0x0002, 0x07BF);
-
-               b43_phy_write(dev, 0x0024, 0x4680);
-               b43_phy_write(dev, 0x0020, 0x0003);
-               b43_phy_write(dev, 0x001D, 0x0F40);
-               b43_phy_write(dev, 0x001F, 0x1C00);
-               b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-                                           & 0x00FF) | 0x0400);
-
-               b43_ofdmtab_write16(dev, 0x3000, 1,
-                                   (b43_ofdmtab_read16(dev, 0x3000, 1)
-                                    & 0x0010) | 0x0008);
-               for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
-                       b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
-               }
-               b43_phy_init_noisescaletbl(dev);
-               for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
-                       b43_ofdmtab_write16(dev, 0x5000, i,
-                                           b43_tab_sigmasqr1[i]);
-               }
-
-               b43_phy_write(dev, 0x0003, 0x1808);
-
-               b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-               b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-               b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-               b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-               b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-               b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
-               b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
-               b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
-               b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
-
-               b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-               b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-               b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+       u16 b, curr_s, best_s = 0xFFFF;
+       int i;
 
-               b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-               b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-               break;
-       default:
-               B43_WARN_ON(1);
+       b43_phy_write(dev, B43_PHY_CRS0,
+               b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
+       b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+               b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
+       b43_phy_write(dev, B43_PHY_OFDM(0x82),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
+       b43_radio_write16(dev, 0x0009,
+               b43_radio_read16(dev, 0x0009) | 0x0080);
+       b43_radio_write16(dev, 0x0012,
+               (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
+       b43_wa_initgains(dev);
+       b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
+       b = b43_phy_read(dev, B43_PHY_PWRDOWN);
+       b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
+       b43_radio_write16(dev, 0x0004,
+               b43_radio_read16(dev, 0x0004) | 0x0004);
+       for (i = 0x10; i <= 0x20; i++) {
+               b43_radio_write16(dev, 0x0013, i);
+               curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
+               if (!curr_s) {
+                       best_s = 0x0000;
+                       break;
+               } else if (curr_s >= 0x0080)
+                       curr_s = 0x0100 - curr_s;
+               if (curr_s < best_s)
+                       best_s = curr_s;
        }
+       b43_phy_write(dev, B43_PHY_PWRDOWN, b);
+       b43_radio_write16(dev, 0x0004,
+               b43_radio_read16(dev, 0x0004) & 0xFFFB);
+       b43_radio_write16(dev, 0x0013, best_s);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
+       b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
+       b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
+       b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
+       b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
+       b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
+       b43_phy_write(dev, B43_PHY_OFDM(0xBB),
+               (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
+       b43_phy_write(dev, B43_PHY_OFDM61,
+               (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
+       b43_phy_write(dev, B43_PHY_OFDM(0x13),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
+       b43_phy_write(dev, B43_PHY_OFDM(0x14),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
+       for (i = 0; i < 6; i++)
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
+       b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
+       b43_phy_write(dev, B43_PHY_CRS0,
+               b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 }
 
 /* Initialize APHY. This is also called for the GPHY in some cases. */
@@ -1130,64 +881,54 @@ static void b43_phy_inita(struct b43_wldev *dev)
 {
        struct ssb_bus *bus = dev->dev->bus;
        struct b43_phy *phy = &dev->phy;
-       u16 tval;
 
        might_sleep();
 
-       if (phy->type == B43_PHYTYPE_A) {
-               b43_phy_setupa(dev);
-       } else {
-               b43_phy_setupg(dev);
-               if (phy->gmode &&
-                   (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
-                       b43_phy_write(dev, 0x046E, 0x03CF);
-               return;
+       if (phy->rev >= 6) {
+               if (phy->type == B43_PHYTYPE_A)
+                       b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+                               b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
+               if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+                       b43_phy_write(dev, B43_PHY_ENCORE,
+                               b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
+               else
+                       b43_phy_write(dev, B43_PHY_ENCORE,
+                               b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
        }
 
-       b43_phy_write(dev, B43_PHY_A_CRS,
-                     (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
-       b43_phy_write(dev, 0x0034, 0x0001);
+       b43_wa_all(dev);
 
-       //TODO: RSSI AGC
-       b43_phy_write(dev, B43_PHY_A_CRS,
-                     b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
-       b43_radio_init2060(dev);
+       if (phy->type == B43_PHYTYPE_A) {
+               if (phy->gmode && (phy->rev < 3))
+                       b43_phy_write(dev, 0x0034,
+                               b43_phy_read(dev, 0x0034) | 0x0001);
+               b43_phy_rssiagc(dev, 0);
 
-       if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-           ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
-            (bus->boardinfo.type == SSB_BOARD_BU4309))) {
-               if (phy->lofcal == 0xFFFF) {
-                       //TODO: LOF Cal
-                       b43_radio_set_tx_iq(dev);
-               } else
-                       b43_radio_write16(dev, 0x001E, phy->lofcal);
-       }
+               b43_phy_write(dev, B43_PHY_CRS0,
+                       b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 
-       b43_phy_write(dev, 0x007A, 0xF111);
+               b43_radio_init2060(dev);
 
-       if (phy->cur_idle_tssi == 0) {
-               b43_radio_write16(dev, 0x0019, 0x0000);
-               b43_radio_write16(dev, 0x0017, 0x0020);
-
-               tval = b43_ofdmtab_read16(dev, 0x3001, 0);
-               if (phy->rev == 1) {
-                       b43_ofdmtab_write16(dev, 0x3001, 0,
-                                           (b43_ofdmtab_read16(dev, 0x3001, 0)
-                                            & 0xFF87)
-                                           | 0x0058);
-               } else {
-                       b43_ofdmtab_write16(dev, 0x3001, 0,
-                                           (b43_ofdmtab_read16(dev, 0x3001, 0)
-                                            & 0xFFC3)
-                                           | 0x002C);
+               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+                   ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+                    (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+                       ; //TODO: A PHY LO
                }
-               b43_dummy_transmission(dev);
-               phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
-               b43_ofdmtab_write16(dev, 0x3001, 0, tval);
 
-               b43_radio_set_txpower_a(dev, 0x0018);
+               if (phy->rev >= 3)
+                       b43_phy_ww(dev);
+
+               hardware_pctl_init_aphy(dev);
+
+               //TODO: radar detection
+       }
+
+       if ((phy->type == B43_PHYTYPE_G) &&
+           (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+               b43_phy_write(dev, B43_PHY_OFDM(0x6E),
+                                 (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
+                                  & 0xE000) | 0x3CF);
        }
-       b43_shm_clear_tssi(dev);
 }
 
 static void b43_phy_initb2(struct b43_wldev *dev)
@@ -1286,7 +1027,7 @@ static void b43_phy_initb4(struct b43_wldev *dev)
        if (phy->radio_ver == 0x2050)
                b43_phy_write(dev, 0x002A, 0x88C2);
        b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
                b43_calc_nrssi_slope(dev);
                b43_calc_nrssi_threshold(dev);
        }
@@ -1433,7 +1174,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x5A, 0x88);
                b43_radio_write16(dev, 0x5B, 0x6B);
                b43_radio_write16(dev, 0x5C, 0x0F);
-               if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
                        b43_radio_write16(dev, 0x5D, 0xFA);
                        b43_radio_write16(dev, 0x5E, 0xD8);
                } else {
@@ -1525,7 +1266,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_phy_write(dev, 0x0062, 0x0007);
                b43_radio_init2050(dev);
                b43_lo_g_measure(dev);
-               if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
                        b43_calc_nrssi_slope(dev);
                        b43_calc_nrssi_threshold(dev);
                }
@@ -1552,14 +1293,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
                backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
        }
-       backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-       backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
-       backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
-       backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
-       backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+       backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+       backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
+       backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
+       backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
+       backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
        backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
        backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
-       backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+       backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
        backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
        backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
        backup_bband = phy->bbatt.att;
@@ -1601,12 +1342,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
                       & 0xFFCF) | 0x10);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x0A),
-                     b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+       b43_phy_write(dev, B43_PHY_CCK(0x0A),
+                     b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
        if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
                b43_phy_write(dev, B43_PHY_ANALOGOVER,
                              b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
@@ -1614,8 +1355,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                              b43_phy_read(dev,
                                           B43_PHY_ANALOGOVERVAL) & 0xFFFB);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x03),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x03))
+       b43_phy_write(dev, B43_PHY_CCK(0x03),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
                       & 0xFF9F) | 0x40);
 
        if (phy->radio_rev == 8) {
@@ -1633,11 +1374,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
        b43_phy_write(dev, B43_PHY_LO_CTL, 0);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x2B),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+       b43_phy_write(dev, B43_PHY_CCK(0x2B),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
                       & 0xFFC0) | 0x01);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+       b43_phy_write(dev, B43_PHY_CCK(0x2B),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
                       & 0xC0FF) | 0x800);
 
        b43_phy_write(dev, B43_PHY_RFOVER,
@@ -1645,7 +1386,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_RFOVERVAL,
                      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
 
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
                if (phy->rev >= 7) {
                        b43_phy_write(dev, B43_PHY_RFOVER,
                                      b43_phy_read(dev, B43_PHY_RFOVER)
@@ -1708,14 +1449,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
                b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
-       b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
-       b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
+       b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
+       b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
        b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
        b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+       b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
        b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
 
        b43_phy_set_baseband_attenuation(dev, backup_bband);
@@ -1807,26 +1548,26 @@ static void b43_phy_initg(struct b43_wldev *dev)
                                          | phy->lo_control->tx_bias);
                }
                if (phy->rev >= 6) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x36),
-                                     (b43_phy_read(dev, B43_PHY_BASE(0x36))
+                       b43_phy_write(dev, B43_PHY_CCK(0x36),
+                                     (b43_phy_read(dev, B43_PHY_CCK(0x36))
                                       & 0x0FFF) | (phy->lo_control->
                                                    tx_bias << 12));
                }
-               if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
                else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
                if (phy->rev < 2)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
                else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
        }
        if (phy->gmode || phy->rev >= 2) {
                b43_lo_g_adjust(dev);
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
        }
 
-       if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+       if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                /* The specs state to update the NRSSI LT with
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
@@ -1995,7 +1736,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        int rfatt_delta, bbatt_delta;
                        int rfatt, bbatt;
                        u8 tx_control;
-                       unsigned long phylock_flags;
 
                        tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
                        v0 = (s8) (tmp & 0x00FF);
@@ -2036,16 +1776,15 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        estimated_pwr =
                            b43_phy_estimate_power_out(dev, average);
 
-                       max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
-                       if ((dev->dev->bus->sprom.r1.
-                            boardflags_lo & B43_BFL_PACTRL)
-                           && (phy->type == B43_PHYTYPE_G))
+                       max_pwr = dev->dev->bus->sprom.maxpwr_bg;
+                       if ((dev->dev->bus->sprom.boardflags_lo
+                           & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
                                max_pwr -= 0x3;
                        if (unlikely(max_pwr <= 0)) {
                                b43warn(dev->wl,
                                        "Invalid max-TX-power value in SPROM.\n");
                                max_pwr = 60;   /* fake it */
-                               dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+                               dev->dev->bus->sprom.maxpwr_bg = max_pwr;
                        }
 
                        /*TODO:
@@ -2103,7 +1842,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                                                    B43_TXCTL_TXMIX;
                                                rfatt += 2;
                                                bbatt += 2;
-                                       } else if (dev->dev->bus->sprom.r1.
+                                       } else if (dev->dev->bus->sprom.
                                                   boardflags_lo &
                                                   B43_BFL_PACTRL) {
                                                bbatt += 4 * (rfatt - 2);
@@ -2127,15 +1866,18 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        phy->bbatt.att = bbatt;
 
                        /* Adjust the hardware */
-                       b43_phy_lock(dev, phylock_flags);
+                       b43_phy_lock(dev);
                        b43_radio_lock(dev);
                        b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
                                          phy->tx_control);
                        b43_lo_g_ctl_mark_cur_used(dev);
                        b43_radio_unlock(dev);
-                       b43_phy_unlock(dev, phylock_flags);
+                       b43_phy_unlock(dev);
                        break;
                }
+       case B43_PHYTYPE_N:
+               b43_nphy_xmitpower(dev);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -2179,13 +1921,13 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
        s8 *dyn_tssi2dbm;
 
        if (phy->type == B43_PHYTYPE_A) {
-               pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
-               pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
-               pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+               pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
+               pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
+               pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
        } else {
-               pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
-               pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
-               pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+               pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
+               pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
+               pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
        }
 
        if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
@@ -2198,23 +1940,23 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
                if (phy->type == B43_PHYTYPE_A) {
-                       if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
-                           (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+                       if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
+                           (s8) dev->dev->bus->sprom.itssi_a != -1)
                                phy->tgt_idle_tssi =
-                                   (s8) (dev->dev->bus->sprom.r1.itssi_a);
+                                   (s8) (dev->dev->bus->sprom.itssi_a);
                        else
                                phy->tgt_idle_tssi = 62;
                } else {
-                       if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
-                           (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+                       if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
+                           (s8) dev->dev->bus->sprom.itssi_bg != -1)
                                phy->tgt_idle_tssi =
-                                   (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+                                   (s8) (dev->dev->bus->sprom.itssi_bg);
                        else
                                phy->tgt_idle_tssi = 62;
                }
                dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
                if (dyn_tssi2dbm == NULL) {
-                       b43err(dev->wl, "Could not allocate memory"
+                       b43err(dev->wl, "Could not allocate memory "
                               "for tssi2dbm table\n");
                        return -ENOMEM;
                }
@@ -2255,41 +1997,44 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 int b43_phy_init(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
-       int err = -ENODEV;
+       bool unsupported = 0;
+       int err = 0;
 
        switch (phy->type) {
        case B43_PHYTYPE_A:
-               if (phy->rev == 2 || phy->rev == 3) {
+               if (phy->rev == 2 || phy->rev == 3)
                        b43_phy_inita(dev);
-                       err = 0;
-               }
+               else
+                       unsupported = 1;
                break;
        case B43_PHYTYPE_B:
                switch (phy->rev) {
                case 2:
                        b43_phy_initb2(dev);
-                       err = 0;
                        break;
                case 4:
                        b43_phy_initb4(dev);
-                       err = 0;
                        break;
                case 5:
                        b43_phy_initb5(dev);
-                       err = 0;
                        break;
                case 6:
                        b43_phy_initb6(dev);
-                       err = 0;
                        break;
+               default:
+                       unsupported = 1;
                }
                break;
        case B43_PHYTYPE_G:
                b43_phy_initg(dev);
-               err = 0;
                break;
+       case B43_PHYTYPE_N:
+               err = b43_phy_initn(dev);
+               break;
+       default:
+               unsupported = 1;
        }
-       if (err)
+       if (unsupported)
                b43err(dev->wl, "Unknown PHYTYPE found\n");
 
        return err;
@@ -2392,6 +2137,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
                    << B43_PHY_BBANDCFG_RXANT_SHIFT;
                b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
                break;
+       case B43_PHYTYPE_N:
+               b43_nphy_set_rxantenna(dev, antenna);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -2421,6 +2169,7 @@ void b43_radio_lock(struct b43_wldev *dev)
        u32 macctl;
 
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
        macctl |= B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit the write and wait for the device
@@ -2437,6 +2186,7 @@ void b43_radio_unlock(struct b43_wldev *dev)
        b43_read16(dev, B43_MMIO_PHY_VER);
        /* unlock */
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
        macctl &= ~B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 }
@@ -2445,9 +2195,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 {
        struct b43_phy *phy = &dev->phy;
 
+       /* Offset 1 is a 32-bit register. */
+       B43_WARN_ON(offset == 1);
+
        switch (phy->type) {
        case B43_PHYTYPE_A:
-               offset |= 0x0040;
+               offset |= 0x40;
                break;
        case B43_PHYTYPE_B:
                if (phy->radio_ver == 0x2053) {
@@ -2463,6 +2216,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
        case B43_PHYTYPE_G:
                offset |= 0x80;
                break;
+       case B43_PHYTYPE_N:
+               offset |= 0x100;
+               break;
+       case B43_PHYTYPE_LP:
+               /* No adjustment required. */
+               break;
+       default:
+               B43_WARN_ON(1);
        }
 
        b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
@@ -2471,11 +2232,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
 {
+       /* Offset 1 is a 32-bit register. */
+       B43_WARN_ON(offset == 1);
+
        b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
 }
 
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+       b43_radio_write16(dev, offset,
+                         b43_radio_read16(dev, offset) & mask);
+}
+
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+       b43_radio_write16(dev, offset,
+                         b43_radio_read16(dev, offset) | set);
+}
+
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+       b43_radio_write16(dev, offset,
+                         (b43_radio_read16(dev, offset) & mask) | set);
+}
+
 static void b43_set_all_gains(struct b43_wldev *dev,
                              s16 first, s16 second, s16 third)
 {
@@ -2605,12 +2386,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
        u8 ret[13];
        unsigned int channel = phy->channel;
        unsigned int i, j, start, end;
-       unsigned long phylock_flags;
 
        if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
                return 0;
 
-       b43_phy_lock(dev, phylock_flags);
+       b43_phy_lock(dev);
        b43_radio_lock(dev);
        b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
        b43_phy_write(dev, B43_PHY_G_CRS,
@@ -2639,7 +2419,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
                        ret[j] = 1;
        }
        b43_radio_unlock(dev);
-       b43_phy_unlock(dev, phylock_flags);
+       b43_phy_unlock(dev);
 
        return ret[channel - 1];
 }
@@ -3114,7 +2894,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        if (phy->radio_ver != 0x2050)
                                return;
                        if (!
-                           (dev->dev->bus->sprom.r1.
+                           (dev->dev->bus->sprom.
                             boardflags_lo & B43_BFL_RSSI))
                                return;
 
@@ -3145,7 +2925,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                }
        case B43_PHYTYPE_G:
                if (!phy->gmode ||
-                   !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+                   !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                        tmp16 = b43_nrssi_hw_read(dev, 0x20);
                        if (tmp16 >= 0x20)
                                tmp16 -= 0x40;
@@ -3667,7 +3447,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
                }
 
                if ((phy->rev < 7) ||
-                   !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+                   !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
                        if (phy_register == B43_PHY_RFOVER) {
                                return 0x1B3;
                        } else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3707,7 +3487,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
                }
        } else {
                if ((phy->rev < 7) ||
-                   !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+                   !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
                        if (phy_register == B43_PHY_RFOVER) {
                                return 0x1B3;
                        } else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3757,10 +3537,10 @@ struct init2050_saved_values {
        u16 radio_52;
        /* PHY registers */
        u16 phy_pgactl;
-       u16 phy_base_5A;
-       u16 phy_base_59;
-       u16 phy_base_58;
-       u16 phy_base_30;
+       u16 phy_cck_5A;
+       u16 phy_cck_59;
+       u16 phy_cck_58;
+       u16 phy_cck_30;
        u16 phy_rfover;
        u16 phy_rfoverval;
        u16 phy_analogover;
@@ -3788,15 +3568,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        sav.radio_51 = b43_radio_read16(dev, 0x51);
        sav.radio_52 = b43_radio_read16(dev, 0x52);
        sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-       sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-       sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
-       sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+       sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+       sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
+       sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
 
        if (phy->type == B43_PHYTYPE_B) {
-               sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+               sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
                sav.reg_3EC = b43_read16(dev, 0x3EC);
 
-               b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+               b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
                b43_write16(dev, 0x3EC, 0x3F3F);
        } else if (phy->gmode || phy->rev >= 2) {
                sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -3847,8 +3627,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_write16(dev, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x03),
-                                     (b43_phy_read(dev, B43_PHY_BASE(0x03))
+                       b43_phy_write(dev, B43_PHY_CCK(0x03),
+                                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
                                       & 0xFFBF) | 0x40);
                }
                b43_write16(dev, B43_MMIO_CHANNEL_EXT,
@@ -3865,7 +3645,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                                                   LPD(0, 1, 1)));
        }
        b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+       b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
        if (phy->gmode || phy->rev >= 2) {
                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                              radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
@@ -3881,12 +3661,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
                                              & 0xFFF0) | 0x0009);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 
        for (i = 0; i < 16; i++) {
-               b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
-               b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-               b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+               b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
+               b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+               b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
                if (phy->gmode || phy->rev >= 2) {
                        b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                      radio2050_rfover_val(dev,
@@ -3912,7 +3692,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
                udelay(20);
                tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-               b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+               b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
                if (phy->gmode || phy->rev >= 2) {
                        b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                      radio2050_rfover_val(dev,
@@ -3923,7 +3703,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        }
        udelay(10);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
        tmp1++;
        tmp1 >>= 9;
 
@@ -3932,9 +3712,9 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x78, radio78);
                udelay(10);
                for (j = 0; j < 16; j++) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
-                       b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-                       b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+                       b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
+                       b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+                       b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
                        if (phy->gmode || phy->rev >= 2) {
                                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                              radio2050_rfover_val(dev,
@@ -3963,7 +3743,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                        b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
                        udelay(10);
                        tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-                       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+                       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
                        if (phy->gmode || phy->rev >= 2) {
                                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                              radio2050_rfover_val(dev,
@@ -3984,16 +3764,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        b43_radio_write16(dev, 0x51, sav.radio_51);
        b43_radio_write16(dev, 0x52, sav.radio_52);
        b43_radio_write16(dev, 0x43, sav.radio_43);
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
        b43_write16(dev, 0x3E6, sav.reg_3E6);
        if (phy->analog != 0)
                b43_write16(dev, 0x3F4, sav.reg_3F4);
        b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
        b43_synth_pu_workaround(dev, phy->channel);
        if (phy->type == B43_PHYTYPE_B) {
-               b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+               b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
                b43_write16(dev, 0x3EC, sav.reg_3EC);
        } else if (phy->gmode) {
                b43_write16(dev, B43_MMIO_PHY_RADIO,
@@ -4103,7 +3883,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
        struct b43_phy *phy = &dev->phy;
        u16 r8, tmp;
        u16 freq;
-       u16 channelcookie;
+       u16 channelcookie, savedcookie;
+       int err = 0;
 
        if (channel == 0xFF) {
                switch (phy->type) {
@@ -4114,6 +3895,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                case B43_PHYTYPE_G:
                        channel = B43_DEFAULT_CHANNEL_BG;
                        break;
+               case B43_PHYTYPE_N:
+                       //FIXME check if we are on 2.4GHz or 5GHz and set a default channel.
+                       channel = 1;
+                       break;
                default:
                        B43_WARN_ON(1);
                }
@@ -4123,13 +3908,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
         * firmware from sending ghost packets.
         */
        channelcookie = channel;
-       if (phy->type == B43_PHYTYPE_A)
+       if (0 /*FIXME on 5Ghz */)
                channelcookie |= 0x100;
+       //FIXME set 40Mhz flag if required
+       savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
 
-       if (phy->type == B43_PHYTYPE_A) {
-               if (channel > 200)
-                       return -EINVAL;
+       switch (phy->type) {
+       case B43_PHYTYPE_A:
+               if (channel > 200) {
+                       err = -EINVAL;
+                       goto out;
+               }
                freq = channel2freq_a(channel);
 
                r8 = b43_radio_read16(dev, 0x0008);
@@ -4176,9 +3966,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                b43_radio_set_tx_iq(dev);
                //TODO: TSSI2dbm workaround
                b43_phy_xmitpower(dev); //FIXME correct?
-       } else {
-               if ((channel < 1) || (channel > 14))
-                       return -EINVAL;
+               break;
+       case B43_PHYTYPE_G:
+               if ((channel < 1) || (channel > 14)) {
+                       err = -EINVAL;
+                       goto out;
+               }
 
                if (synthetic_pu_workaround)
                        b43_synth_pu_workaround(dev, channel);
@@ -4186,7 +3979,7 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
                if (channel == 14) {
-                       if (dev->dev->bus->sprom.r1.country_code ==
+                       if (dev->dev->bus->sprom.country_code ==
                            SSB_SPROM1CCODE_JAPAN)
                                b43_hf_write(dev,
                                             b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -4201,110 +3994,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                                    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
                                    & 0xF7BF);
                }
+               break;
+       case B43_PHYTYPE_N:
+               err = b43_nphy_selectchannel(dev, channel);
+               if (err)
+                       goto out;
+               break;
+       default:
+               B43_WARN_ON(1);
        }
 
        phy->channel = channel;
        /* Wait for the radio to tune to the channel and stabilize. */
        msleep(8);
-
-       return 0;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
-static u16 b43_get_txgain_base_band(u16 txpower)
-{
-       u16 ret;
-
-       B43_WARN_ON(txpower > 63);
-
-       if (txpower >= 54)
-               ret = 2;
-       else if (txpower >= 49)
-               ret = 4;
-       else if (txpower >= 44)
-               ret = 5;
-       else
-               ret = 6;
-
-       return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
-static u16 b43_get_txgain_freq_power_amp(u16 txpower)
-{
-       u16 ret;
-
-       B43_WARN_ON(txpower > 63);
-
-       if (txpower >= 32)
-               ret = 0;
-       else if (txpower >= 25)
-               ret = 1;
-       else if (txpower >= 20)
-               ret = 2;
-       else if (txpower >= 12)
-               ret = 3;
-       else
-               ret = 4;
-
-       return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
-static u16 b43_get_txgain_dac(u16 txpower)
-{
-       u16 ret;
-
-       B43_WARN_ON(txpower > 63);
-
-       if (txpower >= 54)
-               ret = txpower - 53;
-       else if (txpower >= 49)
-               ret = txpower - 42;
-       else if (txpower >= 44)
-               ret = txpower - 37;
-       else if (txpower >= 32)
-               ret = txpower - 32;
-       else if (txpower >= 25)
-               ret = txpower - 20;
-       else if (txpower >= 20)
-               ret = txpower - 13;
-       else if (txpower >= 12)
-               ret = txpower - 8;
-       else
-               ret = txpower;
-
-       return ret;
-}
-
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 pamp, base, dac, t;
-
-       txpower = limit_value(txpower, 0, 63);
-
-       pamp = b43_get_txgain_freq_power_amp(txpower);
-       pamp <<= 5;
-       pamp &= 0x00E0;
-       b43_phy_write(dev, 0x0019, pamp);
-
-       base = b43_get_txgain_base_band(txpower);
-       base &= 0x000F;
-       b43_phy_write(dev, 0x0017, base | 0x0020);
-
-       t = b43_ofdmtab_read16(dev, 0x3000, 1);
-       t &= 0x0007;
-
-       dac = b43_get_txgain_dac(txpower);
-       dac <<= 3;
-       dac |= t;
-
-       b43_ofdmtab_write16(dev, 0x3000, 1, dac);
-
-       phy->txpwr_offset = txpower;
-
-       //TODO: FuncPlaceholder (Adjust BB loft cancel)
+out:
+       if (err) {
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_CHAN, savedcookie);
+       }
+       return err;
 }
 
 void b43_radio_turn_on(struct b43_wldev *dev)
@@ -4344,6 +4052,9 @@ void b43_radio_turn_on(struct b43_wldev *dev)
                err |= b43_radio_selectchannel(dev, channel, 0);
                B43_WARN_ON(err);
                break;
+       case B43_PHYTYPE_N:
+               b43_nphy_radio_turn_on(dev);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -4357,13 +4068,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
        if (!phy->radio_on && !force)
                return;
 
-       if (phy->type == B43_PHYTYPE_A) {
+       switch (phy->type) {
+       case B43_PHYTYPE_N:
+               b43_nphy_radio_turn_off(dev);
+               break;
+       case B43_PHYTYPE_A:
                b43_radio_write16(dev, 0x0004, 0x00FF);
                b43_radio_write16(dev, 0x0005, 0x00FB);
                b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
                b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
-       }
-       if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+               break;
+       case B43_PHYTYPE_G: {
                u16 rfover, rfoverval;
 
                rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -4375,7 +4090,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
                }
                b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
                b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
-       } else
-               b43_phy_write(dev, 0x0015, 0xAA00);
+               break;
+       }
+       default:
+               B43_WARN_ON(1);
+       }
        phy->radio_on = 0;
 }
index c64d74504fc0ad29021bd415471f03f0b4c2b7e0..6d165d8221757d98a957072d133c7683d7f66b3c 100644 (file)
@@ -9,14 +9,21 @@ struct b43_phy;
 /*** PHY Registers ***/
 
 /* Routing */
-#define B43_PHYROUTE_OFDM_GPHY         0x400
-#define B43_PHYROUTE_EXT_GPHY          0x800
-
-/* Base registers. */
-#define B43_PHY_BASE(reg)              (reg)
-/* OFDM (A) registers of a G-PHY */
+#define B43_PHYROUTE                   0x0C00 /* PHY register routing bits mask */
+#define  B43_PHYROUTE_BASE             0x0000 /* Base registers */
+#define  B43_PHYROUTE_OFDM_GPHY                0x0400 /* OFDM register routing for G-PHYs */
+#define  B43_PHYROUTE_EXT_GPHY         0x0800 /* Extended G-PHY registers */
+#define  B43_PHYROUTE_N_BMODE          0x0C00 /* N-PHY BMODE registers */
+
+/* CCK (B-PHY) registers. */
+#define B43_PHY_CCK(reg)               ((reg) | B43_PHYROUTE_BASE)
+/* N-PHY registers. */
+#define B43_PHY_N(reg)                 ((reg) | B43_PHYROUTE_BASE)
+/* N-PHY BMODE registers. */
+#define B43_PHY_N_BMODE(reg)           ((reg) | B43_PHYROUTE_N_BMODE)
+/* OFDM (A-PHY) registers. */
 #define B43_PHY_OFDM(reg)              ((reg) | B43_PHYROUTE_OFDM_GPHY)
-/* Extended G-PHY registers */
+/* Extended G-PHY registers. */
 #define B43_PHY_EXTG(reg)              ((reg) | B43_PHYROUTE_EXT_GPHY)
 
 /* OFDM (A) PHY Registers */
@@ -25,10 +32,13 @@ struct b43_phy;
 #define  B43_PHY_BBANDCFG_RXANT                0x180   /* RX Antenna selection */
 #define  B43_PHY_BBANDCFG_RXANT_SHIFT  7
 #define B43_PHY_PWRDOWN                        B43_PHY_OFDM(0x03)      /* Powerdown */
-#define B43_PHY_CRSTHRES1              B43_PHY_OFDM(0x06)      /* CRS Threshold 1 */
+#define B43_PHY_CRSTHRES1_R1           B43_PHY_OFDM(0x06)      /* CRS Threshold 1 (phy.rev 1 only) */
 #define B43_PHY_LNAHPFCTL              B43_PHY_OFDM(0x1C)      /* LNA/HPF control */
+#define B43_PHY_LPFGAINCTL             B43_PHY_OFDM(0x20)      /* LPF Gain control */
 #define B43_PHY_ADIVRELATED            B43_PHY_OFDM(0x27)      /* FIXME rename */
 #define B43_PHY_CRS0                   B43_PHY_OFDM(0x29)
+#define  B43_PHY_CRS0_EN               0x4000
+#define B43_PHY_PEAK_COUNT             B43_PHY_OFDM(0x30)
 #define B43_PHY_ANTDWELL               B43_PHY_OFDM(0x2B)      /* Antenna dwell */
 #define  B43_PHY_ANTDWELL_AUTODIV1     0x0100  /* Automatic RX diversity start antenna */
 #define B43_PHY_ENCORE                 B43_PHY_OFDM(0x49)      /* "Encore" (RangeMax / BroadRange) */
@@ -37,6 +47,7 @@ struct b43_phy;
 #define B43_PHY_OFDM61                 B43_PHY_OFDM(0x61)      /* FIXME rename */
 #define  B43_PHY_OFDM61_10             0x0010  /* FIXME rename */
 #define B43_PHY_IQBAL                  B43_PHY_OFDM(0x69)      /* I/Q balance */
+#define B43_PHY_BBTXDC_BIAS            B43_PHY_OFDM(0x6B)      /* Baseband TX DC bias */
 #define B43_PHY_OTABLECTL              B43_PHY_OFDM(0x72)      /* OFDM table control (see below) */
 #define  B43_PHY_OTABLEOFF             0x03FF  /* OFDM table offset (see below) */
 #define  B43_PHY_OTABLENR              0xFC00  /* OFDM table number (see below) */
@@ -44,6 +55,9 @@ struct b43_phy;
 #define B43_PHY_OTABLEI                        B43_PHY_OFDM(0x73)      /* OFDM table data I */
 #define B43_PHY_OTABLEQ                        B43_PHY_OFDM(0x74)      /* OFDM table data Q */
 #define B43_PHY_HPWR_TSSICTL           B43_PHY_OFDM(0x78)      /* Hardware power TSSI control */
+#define B43_PHY_ADCCTL                 B43_PHY_OFDM(0x7A)      /* ADC control */
+#define B43_PHY_IDLE_TSSI              B43_PHY_OFDM(0x7B)
+#define B43_PHY_A_TEMP_SENSE           B43_PHY_OFDM(0x7C)      /* A PHY temperature sense */
 #define B43_PHY_NRSSITHRES             B43_PHY_OFDM(0x8A)      /* NRSSI threshold */
 #define B43_PHY_ANTWRSETT              B43_PHY_OFDM(0x8C)      /* Antenna WR settle */
 #define  B43_PHY_ANTWRSETT_ARXDIV      0x2000  /* Automatic RX diversity enabled */
@@ -54,33 +68,35 @@ struct b43_phy;
 #define B43_PHY_N1N2GAIN               B43_PHY_OFDM(0xA2)
 #define B43_PHY_CLIPTHRES              B43_PHY_OFDM(0xA3)
 #define B43_PHY_CLIPN1P2THRES          B43_PHY_OFDM(0xA4)
+#define B43_PHY_CCKSHIFTBITS_WA                B43_PHY_OFDM(0xA5)      /* CCK shiftbits workaround, FIXME rename */
+#define B43_PHY_CCKSHIFTBITS           B43_PHY_OFDM(0xA7)      /* FIXME rename */
 #define B43_PHY_DIVSRCHIDX             B43_PHY_OFDM(0xA8)      /* Divider search gain/index */
 #define B43_PHY_CLIPP2THRES            B43_PHY_OFDM(0xA9)
 #define B43_PHY_CLIPP3THRES            B43_PHY_OFDM(0xAA)
 #define B43_PHY_DIVP1P2GAIN            B43_PHY_OFDM(0xAB)
 #define B43_PHY_DIVSRCHGAINBACK                B43_PHY_OFDM(0xAD)      /* Divider search gain back */
 #define B43_PHY_DIVSRCHGAINCHNG                B43_PHY_OFDM(0xAE)      /* Divider search gain change */
-#define B43_PHY_CRSTHRES1_R1           B43_PHY_OFDM(0xC0)      /* CRS Threshold 1 (rev 1 only) */
-#define B43_PHY_CRSTHRES2_R1           B43_PHY_OFDM(0xC1)      /* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_CRSTHRES1              B43_PHY_OFDM(0xC0)      /* CRS Threshold 1 (phy.rev >= 2 only) */
+#define B43_PHY_CRSTHRES2              B43_PHY_OFDM(0xC1)      /* CRS Threshold 2 (phy.rev >= 2 only) */
 #define B43_PHY_TSSIP_LTBASE           B43_PHY_OFDM(0x380)     /* TSSI power lookup table base */
 #define B43_PHY_DC_LTBASE              B43_PHY_OFDM(0x3A0)     /* DC lookup table base */
 #define B43_PHY_GAIN_LTBASE            B43_PHY_OFDM(0x3C0)     /* Gain lookup table base */
 
 /* CCK (B) PHY Registers */
-#define B43_PHY_VERSION_CCK            B43_PHY_BASE(0x00)      /* Versioning register for B-PHY */
-#define B43_PHY_CCKBBANDCFG            B43_PHY_BASE(0x01)      /* Contains antenna 0/1 control bit */
-#define B43_PHY_PGACTL                 B43_PHY_BASE(0x15)      /* PGA control */
+#define B43_PHY_VERSION_CCK            B43_PHY_CCK(0x00)       /* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG            B43_PHY_CCK(0x01)       /* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL                 B43_PHY_CCK(0x15)       /* PGA control */
 #define  B43_PHY_PGACTL_LPF            0x1000  /* Low pass filter (?) */
 #define  B43_PHY_PGACTL_LOWBANDW       0x0040  /* Low bandwidth flag */
 #define  B43_PHY_PGACTL_UNKNOWN                0xEFA0
-#define B43_PHY_FBCTL1                 B43_PHY_BASE(0x18)      /* Frequency bandwidth control 1 */
-#define B43_PHY_ITSSI                  B43_PHY_BASE(0x29)      /* Idle TSSI */
-#define B43_PHY_LO_LEAKAGE             B43_PHY_BASE(0x2D)      /* Measured LO leakage */
-#define B43_PHY_ENERGY                 B43_PHY_BASE(0x33)      /* Energy */
-#define B43_PHY_SYNCCTL                        B43_PHY_BASE(0x35)
-#define B43_PHY_FBCTL2                 B43_PHY_BASE(0x38)      /* Frequency bandwidth control 2 */
-#define B43_PHY_DACCTL                 B43_PHY_BASE(0x60)      /* DAC control */
-#define B43_PHY_RCCALOVER              B43_PHY_BASE(0x78)      /* RC calibration override */
+#define B43_PHY_FBCTL1                 B43_PHY_CCK(0x18)       /* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI                  B43_PHY_CCK(0x29)       /* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE             B43_PHY_CCK(0x2D)       /* Measured LO leakage */
+#define B43_PHY_ENERGY                 B43_PHY_CCK(0x33)       /* Energy */
+#define B43_PHY_SYNCCTL                        B43_PHY_CCK(0x35)
+#define B43_PHY_FBCTL2                 B43_PHY_CCK(0x38)       /* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL                 B43_PHY_CCK(0x60)       /* DAC control */
+#define B43_PHY_RCCALOVER              B43_PHY_CCK(0x78)       /* RC calibration override */
 
 /* Extended G-PHY Registers */
 #define B43_PHY_CLASSCTL               B43_PHY_EXTG(0x02)      /* Classify control */
@@ -125,13 +141,14 @@ struct b43_phy;
 #define B43_OFDMTAB_DC                 B43_OFDMTAB(0x0E, 7)
 #define B43_OFDMTAB_PWRDYN2            B43_OFDMTAB(0x0E, 12)
 #define B43_OFDMTAB_LNAGAIN            B43_OFDMTAB(0x0E, 13)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_0F         B43_OFDMTAB(0x0F, 0)    //TODO rename
+#define B43_OFDMTAB_UNKNOWN_APHY       B43_OFDMTAB(0x0F, 7)    //TODO rename
 #define B43_OFDMTAB_LPFGAIN            B43_OFDMTAB(0x0F, 12)
 #define B43_OFDMTAB_RSSI               B43_OFDMTAB(0x10, 0)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_11         B43_OFDMTAB(0x11, 4)    //TODO rename
 #define B43_OFDMTAB_AGC1_R1            B43_OFDMTAB(0x13, 0)
-#define B43_OFDMTAB_GAINX_R1           B43_OFDMTAB(0x14, 0)    //TODO rename
-#define B43_OFDMTAB_MINSIGSQ           B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_GAINX_R1           B43_OFDMTAB(0x14, 0)    //TODO remove!
+#define B43_OFDMTAB_MINSIGSQ           B43_OFDMTAB(0x14, 0)
 #define B43_OFDMTAB_AGC3_R1            B43_OFDMTAB(0x15, 0)
 #define B43_OFDMTAB_WRSSI_R1           B43_OFDMTAB(0x15, 4)
 #define B43_OFDMTAB_TSSI               B43_OFDMTAB(0x15, 0)
@@ -163,6 +180,8 @@ enum {
        B43_ANTENNA1,           /* Antenna 0 */
        B43_ANTENNA_AUTO1,      /* Automatic, starting with antenna 1 */
        B43_ANTENNA_AUTO0,      /* Automatic, starting with antenna 0 */
+       B43_ANTENNA2,
+       B43_ANTENNA3 = 8,
 
        B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
        B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
@@ -182,21 +201,21 @@ enum {
 #define B43_PHYVER_TYPE_SHIFT          8
 #define B43_PHYVER_VERSION             0x00FF
 
-void b43_raw_phy_lock(struct b43_wldev *dev);
-#define b43_phy_lock(dev, flags) \
-       do {                                    \
-               local_irq_save(flags);          \
-               b43_raw_phy_lock(dev);  \
-       } while (0)
-void b43_raw_phy_unlock(struct b43_wldev *dev);
-#define b43_phy_unlock(dev, flags) \
-       do {                                    \
-               b43_raw_phy_unlock(dev);        \
-               local_irq_restore(flags);       \
-       } while (0)
+void b43_phy_lock(struct b43_wldev *dev);
+void b43_phy_unlock(struct b43_wldev *dev);
+
 
+/* Read a value from a PHY register */
 u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+/* Write a value to a PHY register */
 void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a PHY register with a mask */
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a PHY register with a bitmap */
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
 
@@ -260,8 +279,18 @@ extern const u8 b43_radio_channel_codes_bg[];
 void b43_radio_lock(struct b43_wldev *dev);
 void b43_radio_unlock(struct b43_wldev *dev);
 
+
+/* Read a value from a 16bit radio register */
 u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+/* Write a value to a 16bit radio register */
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a 16bit radio register with a mask */
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a 16bit radio register with a bitmap */
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 u16 b43_radio_init2050(struct b43_wldev *dev);
 void b43_radio_init2060(struct b43_wldev *dev);
diff --git a/package/b43/src/pio.c b/package/b43/src/pio.c
deleted file mode 100644 (file)
index 67752a2..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
-
-  Broadcom B43 wireless driver
-
-  PIO Transmission
-
-  Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#include "b43.h"
-#include "pio.h"
-#include "main.h"
-#include "xmit.h"
-
-#include <linux/delay.h>
-
-static void tx_start(struct b43_pioqueue *queue)
-{
-       b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
-}
-
-static void tx_octet(struct b43_pioqueue *queue, u8 octet)
-{
-       if (queue->need_workarounds) {
-               b43_pio_write(queue, B43_PIO_TXDATA, octet);
-               b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-       } else {
-               b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-               b43_pio_write(queue, B43_PIO_TXDATA, octet);
-       }
-}
-
-static u16 tx_get_next_word(const u8 * txhdr,
-                           const u8 * packet,
-                           size_t txhdr_size, unsigned int *pos)
-{
-       const u8 *source;
-       unsigned int i = *pos;
-       u16 ret;
-
-       if (i < txhdr_size) {
-               source = txhdr;
-       } else {
-               source = packet;
-               i -= txhdr_size;
-       }
-       ret = le16_to_cpu(*((__le16 *)(source + i)));
-       *pos += 2;
-
-       return ret;
-}
-
-static void tx_data(struct b43_pioqueue *queue,
-                   u8 * txhdr, const u8 * packet, unsigned int octets)
-{
-       u16 data;
-       unsigned int i = 0;
-
-       if (queue->need_workarounds) {
-               data = tx_get_next_word(txhdr, packet,
-                                       sizeof(struct b43_txhdr_fw4), &i);
-               b43_pio_write(queue, B43_PIO_TXDATA, data);
-       }
-       b43_pio_write(queue, B43_PIO_TXCTL,
-                     B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
-       while (i < octets - 1) {
-               data = tx_get_next_word(txhdr, packet,
-                                       sizeof(struct b43_txhdr_fw4), &i);
-               b43_pio_write(queue, B43_PIO_TXDATA, data);
-       }
-       if (octets % 2)
-               tx_octet(queue,
-                        packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
-}
-
-static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
-{
-       if (queue->need_workarounds) {
-               b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
-               b43_pio_write(queue, B43_PIO_TXCTL,
-                             B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
-       } else {
-               b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
-       }
-}
-
-static u16 generate_cookie(struct b43_pioqueue *queue,
-                          struct b43_pio_txpacket *packet)
-{
-       u16 cookie = 0x0000;
-       u16 packetindex;
-
-       /* We use the upper 4 bits for the PIO
-        * controller ID and the lower 12 bits
-        * for the packet index (in the cache).
-        */
-       switch (queue->mmio_base) {
-       case B43_MMIO_PIO1_BASE:
-               break;
-       case B43_MMIO_PIO2_BASE:
-               cookie = 0x1000;
-               break;
-       case B43_MMIO_PIO3_BASE:
-               cookie = 0x2000;
-               break;
-       case B43_MMIO_PIO4_BASE:
-               cookie = 0x3000;
-               break;
-       default:
-               B43_WARN_ON(1);
-       }
-       packetindex = packet->index;
-       B43_WARN_ON(packetindex & ~0x0FFF);
-       cookie |= (u16) packetindex;
-
-       return cookie;
-}
-
-static
-struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
-                                 u16 cookie, struct b43_pio_txpacket **packet)
-{
-       struct b43_pio *pio = &dev->pio;
-       struct b43_pioqueue *queue = NULL;
-       int packetindex;
-
-       switch (cookie & 0xF000) {
-       case 0x0000:
-               queue = pio->queue0;
-               break;
-       case 0x1000:
-               queue = pio->queue1;
-               break;
-       case 0x2000:
-               queue = pio->queue2;
-               break;
-       case 0x3000:
-               queue = pio->queue3;
-               break;
-       default:
-               B43_WARN_ON(1);
-       }
-       packetindex = (cookie & 0x0FFF);
-       B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
-       *packet = &(queue->tx_packets_cache[packetindex]);
-
-       return queue;
-}
-
-union txhdr_union {
-       struct b43_txhdr_fw4 txhdr_fw4;
-};
-
-static void pio_tx_write_fragment(struct b43_pioqueue *queue,
-                                 struct sk_buff *skb,
-                                 struct b43_pio_txpacket *packet,
-                                 size_t txhdr_size)
-{
-       union txhdr_union txhdr_data;
-       u8 *txhdr = NULL;
-       unsigned int octets;
-
-       txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
-
-       B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-       b43_generate_txhdr(queue->dev,
-                          txhdr, skb->data, skb->len,
-                          &packet->txstat.control,
-                          generate_cookie(queue, packet));
-
-       tx_start(queue);
-       octets = skb->len + txhdr_size;
-       if (queue->need_workarounds)
-               octets--;
-       tx_data(queue, txhdr, (u8 *) skb->data, octets);
-       tx_complete(queue, skb);
-}
-
-static void free_txpacket(struct b43_pio_txpacket *packet)
-{
-       struct b43_pioqueue *queue = packet->queue;
-
-       if (packet->skb)
-               dev_kfree_skb_any(packet->skb);
-       list_move(&packet->list, &queue->txfree);
-       queue->nr_txfree++;
-}
-
-static int pio_tx_packet(struct b43_pio_txpacket *packet)
-{
-       struct b43_pioqueue *queue = packet->queue;
-       struct sk_buff *skb = packet->skb;
-       u16 octets;
-
-       octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
-       if (queue->tx_devq_size < octets) {
-               b43warn(queue->dev->wl, "PIO queue too small. "
-                       "Dropping packet.\n");
-               /* Drop it silently (return success) */
-               free_txpacket(packet);
-               return 0;
-       }
-       B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
-       B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
-       /* Check if there is sufficient free space on the device
-        * TX queue. If not, return and let the TX tasklet
-        * retry later.
-        */
-       if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
-               return -EBUSY;
-       if (queue->tx_devq_used + octets > queue->tx_devq_size)
-               return -EBUSY;
-       /* Now poke the device. */
-       pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
-
-       /* Account for the packet size.
-        * (We must not overflow the device TX queue)
-        */
-       queue->tx_devq_packets++;
-       queue->tx_devq_used += octets;
-
-       /* Transmission started, everything ok, move the
-        * packet to the txrunning list.
-        */
-       list_move_tail(&packet->list, &queue->txrunning);
-
-       return 0;
-}
-
-static void tx_tasklet(unsigned long d)
-{
-       struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
-       struct b43_wldev *dev = queue->dev;
-       unsigned long flags;
-       struct b43_pio_txpacket *packet, *tmp_packet;
-       int err;
-       u16 txctl;
-
-       spin_lock_irqsave(&dev->wl->irq_lock, flags);
-       if (queue->tx_frozen)
-               goto out_unlock;
-       txctl = b43_pio_read(queue, B43_PIO_TXCTL);
-       if (txctl & B43_PIO_TXCTL_SUSPEND)
-               goto out_unlock;
-
-       list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
-               /* Try to transmit the packet. This can fail, if
-                * the device queue is full. In case of failure, the
-                * packet is left in the txqueue.
-                * If transmission succeed, the packet is moved to txrunning.
-                * If it is impossible to transmit the packet, it
-                * is dropped.
-                */
-               err = pio_tx_packet(packet);
-               if (err)
-                       break;
-       }
-      out_unlock:
-       spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-}
-
-static void setup_txqueues(struct b43_pioqueue *queue)
-{
-       struct b43_pio_txpacket *packet;
-       int i;
-
-       queue->nr_txfree = B43_PIO_MAXTXPACKETS;
-       for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
-               packet = &(queue->tx_packets_cache[i]);
-
-               packet->queue = queue;
-               INIT_LIST_HEAD(&packet->list);
-               packet->index = i;
-
-               list_add(&packet->list, &queue->txfree);
-       }
-}
-
-static
-struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
-                                       u16 pio_mmio_base)
-{
-       struct b43_pioqueue *queue;
-       u16 qsize;
-
-       queue = kzalloc(sizeof(*queue), GFP_KERNEL);
-       if (!queue)
-               goto out;
-
-       queue->dev = dev;
-       queue->mmio_base = pio_mmio_base;
-       queue->need_workarounds = (dev->dev->id.revision < 3);
-
-       INIT_LIST_HEAD(&queue->txfree);
-       INIT_LIST_HEAD(&queue->txqueue);
-       INIT_LIST_HEAD(&queue->txrunning);
-       tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
-
-       b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
-                   & ~B43_MACCTL_BE);
-
-       qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
-       if (qsize == 0) {
-               b43err(dev->wl, "This card does not support PIO "
-                      "operation mode. Please use DMA mode "
-                      "(module parameter pio=0).\n");
-               goto err_freequeue;
-       }
-       if (qsize <= B43_PIO_TXQADJUST) {
-               b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
-               goto err_freequeue;
-       }
-       qsize -= B43_PIO_TXQADJUST;
-       queue->tx_devq_size = qsize;
-
-       setup_txqueues(queue);
-
-      out:
-       return queue;
-
-      err_freequeue:
-       kfree(queue);
-       queue = NULL;
-       goto out;
-}
-
-static void cancel_transfers(struct b43_pioqueue *queue)
-{
-       struct b43_pio_txpacket *packet, *tmp_packet;
-
-       tasklet_disable(&queue->txtask);
-
-       list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
-           free_txpacket(packet);
-       list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
-           free_txpacket(packet);
-}
-
-static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
-{
-       if (!queue)
-               return;
-
-       cancel_transfers(queue);
-       kfree(queue);
-}
-
-void b43_pio_free(struct b43_wldev *dev)
-{
-       struct b43_pio *pio;
-
-       if (!b43_using_pio(dev))
-               return;
-       pio = &dev->pio;
-
-       b43_destroy_pioqueue(pio->queue3);
-       pio->queue3 = NULL;
-       b43_destroy_pioqueue(pio->queue2);
-       pio->queue2 = NULL;
-       b43_destroy_pioqueue(pio->queue1);
-       pio->queue1 = NULL;
-       b43_destroy_pioqueue(pio->queue0);
-       pio->queue0 = NULL;
-}
-
-int b43_pio_init(struct b43_wldev *dev)
-{
-       struct b43_pio *pio = &dev->pio;
-       struct b43_pioqueue *queue;
-       int err = -ENOMEM;
-
-       queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
-       if (!queue)
-               goto out;
-       pio->queue0 = queue;
-
-       queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
-       if (!queue)
-               goto err_destroy0;
-       pio->queue1 = queue;
-
-       queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
-       if (!queue)
-               goto err_destroy1;
-       pio->queue2 = queue;
-
-       queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
-       if (!queue)
-               goto err_destroy2;
-       pio->queue3 = queue;
-
-       if (dev->dev->id.revision < 3)
-               dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
-
-       b43dbg(dev->wl, "PIO initialized\n");
-       err = 0;
-      out:
-       return err;
-
-      err_destroy2:
-       b43_destroy_pioqueue(pio->queue2);
-       pio->queue2 = NULL;
-      err_destroy1:
-       b43_destroy_pioqueue(pio->queue1);
-       pio->queue1 = NULL;
-      err_destroy0:
-       b43_destroy_pioqueue(pio->queue0);
-       pio->queue0 = NULL;
-       goto out;
-}
-
-int b43_pio_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-       struct b43_pioqueue *queue = dev->pio.queue1;
-       struct b43_pio_txpacket *packet;
-
-       B43_WARN_ON(queue->tx_suspended);
-       B43_WARN_ON(list_empty(&queue->txfree));
-
-       packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
-       packet->skb = skb;
-
-       memset(&packet->txstat, 0, sizeof(packet->txstat));
-       memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
-       list_move_tail(&packet->list, &queue->txqueue);
-       queue->nr_txfree--;
-       queue->nr_tx_packets++;
-       B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
-
-       tasklet_schedule(&queue->txtask);
-
-       return 0;
-}
-
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-                            const struct b43_txstatus *status)
-{
-       struct b43_pioqueue *queue;
-       struct b43_pio_txpacket *packet;
-
-       queue = parse_cookie(dev, status->cookie, &packet);
-       if (B43_WARN_ON(!queue))
-               return;
-
-       queue->tx_devq_packets--;
-       queue->tx_devq_used -=
-           (packet->skb->len + sizeof(struct b43_txhdr_fw4));
-
-       if (status->acked) {
-               packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
-       } else {
-               if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
-                       packet->txstat.excessive_retries = 1;
-       }
-       if (status->frame_count == 0) {
-               /* The frame was not transmitted at all. */
-               packet->txstat.retry_count = 0;
-       } else
-               packet->txstat.retry_count = status->frame_count - 1;
-       ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
-                                   &(packet->txstat));
-       packet->skb = NULL;
-
-       free_txpacket(packet);
-       /* If there are packets on the txqueue, poke the tasklet
-        * to transmit them.
-        */
-       if (!list_empty(&queue->txqueue))
-               tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-                         struct ieee80211_tx_queue_stats *stats)
-{
-       struct b43_pio *pio = &dev->pio;
-       struct b43_pioqueue *queue;
-       struct ieee80211_tx_queue_stats_data *data;
-
-       queue = pio->queue1;
-       data = &(stats->data[0]);
-       data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
-       data->limit = B43_PIO_MAXTXPACKETS;
-       data->count = queue->nr_tx_packets;
-}
-
-static void pio_rx_error(struct b43_pioqueue *queue,
-                        int clear_buffers, const char *error)
-{
-       int i;
-
-       b43err(queue->dev->wl, "PIO RX error: %s\n", error);
-       b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
-       if (clear_buffers) {
-               B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
-               for (i = 0; i < 15; i++) {
-                       /* Dummy read. */
-                       b43_pio_read(queue, B43_PIO_RXDATA);
-               }
-       }
-}
-
-void b43_pio_rx(struct b43_pioqueue *queue)
-{
-       __le16 preamble[21] = { 0 };
-       struct b43_rxhdr_fw4 *rxhdr;
-       u16 tmp, len;
-       u32 macstat;
-       int i, preamble_readwords;
-       struct sk_buff *skb;
-
-       tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-       if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
-               return;
-       b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
-
-       for (i = 0; i < 10; i++) {
-               tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-               if (tmp & B43_PIO_RXCTL_READY)
-                       goto data_ready;
-               udelay(10);
-       }
-       b43dbg(queue->dev->wl, "PIO RX timed out\n");
-       return;
-data_ready:
-
-       len = b43_pio_read(queue, B43_PIO_RXDATA);
-       if (unlikely(len > 0x700)) {
-               pio_rx_error(queue, 0, "len > 0x700");
-               return;
-       }
-       if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
-               pio_rx_error(queue, 0, "len == 0");
-               return;
-       }
-       preamble[0] = cpu_to_le16(len);
-       if (queue->mmio_base == B43_MMIO_PIO4_BASE)
-               preamble_readwords = 14 / sizeof(u16);
-       else
-               preamble_readwords = 18 / sizeof(u16);
-       for (i = 0; i < preamble_readwords; i++) {
-               tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-               preamble[i + 1] = cpu_to_le16(tmp);
-       }
-       rxhdr = (struct b43_rxhdr_fw4 *)preamble;
-       macstat = le32_to_cpu(rxhdr->mac_status);
-       if (macstat & B43_RX_MAC_FCSERR) {
-               pio_rx_error(queue,
-                            (queue->mmio_base == B43_MMIO_PIO1_BASE),
-                            "Frame FCS error");
-               return;
-       }
-       if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
-               /* We received an xmit status. */
-               struct b43_hwtxstatus *hw;
-
-               hw = (struct b43_hwtxstatus *)(preamble + 1);
-               b43_handle_hwtxstatus(queue->dev, hw);
-
-               return;
-       }
-
-       skb = dev_alloc_skb(len);
-       if (unlikely(!skb)) {
-               pio_rx_error(queue, 1, "OOM");
-               return;
-       }
-       skb_put(skb, len);
-       for (i = 0; i < len - 1; i += 2) {
-               tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-               *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
-       }
-       if (len % 2) {
-               tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-               skb->data[len - 1] = (tmp & 0x00FF);
-/* The specs say the following is required, but
- * it is wrong and corrupts the PLCP. If we don't do
- * this, the PLCP seems to be correct. So ifdef it out for now.
- */
-#if 0
-               if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
-                       skb->data[2] = (tmp & 0xFF00) >> 8;
-               else
-                       skb->data[0] = (tmp & 0xFF00) >> 8;
-#endif
-       }
-       b43_rx(queue->dev, skb, rxhdr);
-}
-
-void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-       b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
-       b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-                     | B43_PIO_TXCTL_SUSPEND);
-}
-
-void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-       b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-                     & ~B43_PIO_TXCTL_SUSPEND);
-       b43_power_saving_ctl_bits(queue->dev, 0);
-       tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-       struct b43_pio *pio;
-
-       B43_WARN_ON(!b43_using_pio(dev));
-       pio = &dev->pio;
-       pio->queue0->tx_frozen = 1;
-       pio->queue1->tx_frozen = 1;
-       pio->queue2->tx_frozen = 1;
-       pio->queue3->tx_frozen = 1;
-}
-
-void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-       struct b43_pio *pio;
-
-       B43_WARN_ON(!b43_using_pio(dev));
-       pio = &dev->pio;
-       pio->queue0->tx_frozen = 0;
-       pio->queue1->tx_frozen = 0;
-       pio->queue2->tx_frozen = 0;
-       pio->queue3->tx_frozen = 0;
-       if (!list_empty(&pio->queue0->txqueue))
-               tasklet_schedule(&pio->queue0->txtask);
-       if (!list_empty(&pio->queue1->txqueue))
-               tasklet_schedule(&pio->queue1->txtask);
-       if (!list_empty(&pio->queue2->txqueue))
-               tasklet_schedule(&pio->queue2->txtask);
-       if (!list_empty(&pio->queue3->txqueue))
-               tasklet_schedule(&pio->queue3->txtask);
-}
diff --git a/package/b43/src/pio.h b/package/b43/src/pio.h
deleted file mode 100644 (file)
index 3488f24..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef B43_PIO_H_
-#define B43_PIO_H_
-
-#include "b43.h"
-
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/skbuff.h>
-
-#define B43_PIO_TXCTL          0x00
-#define B43_PIO_TXDATA         0x02
-#define B43_PIO_TXQBUFSIZE             0x04
-#define B43_PIO_RXCTL          0x08
-#define B43_PIO_RXDATA         0x0A
-
-#define B43_PIO_TXCTL_WRITELO  (1 << 0)
-#define B43_PIO_TXCTL_WRITEHI  (1 << 1)
-#define B43_PIO_TXCTL_COMPLETE (1 << 2)
-#define B43_PIO_TXCTL_INIT             (1 << 3)
-#define B43_PIO_TXCTL_SUSPEND  (1 << 7)
-
-#define B43_PIO_RXCTL_DATAAVAILABLE    (1 << 0)
-#define B43_PIO_RXCTL_READY            (1 << 1)
-
-/* PIO constants */
-#define B43_PIO_MAXTXDEVQPACKETS       31
-#define B43_PIO_TXQADJUST              80
-
-/* PIO tuning knobs */
-#define B43_PIO_MAXTXPACKETS   256
-
-#ifdef CONFIG_B43_PIO
-
-struct b43_pioqueue;
-struct b43_xmitstatus;
-
-struct b43_pio_txpacket {
-       struct b43_pioqueue *queue;
-       struct sk_buff *skb;
-       struct ieee80211_tx_status txstat;
-       struct list_head list;
-       u16 index; /* Index in the tx_packets_cache */
-};
-
-struct b43_pioqueue {
-       struct b43_wldev *dev;
-       u16 mmio_base;
-
-       bool tx_suspended;
-       bool tx_frozen;
-       bool need_workarounds;  /* Workarounds needed for core.rev < 3 */
-
-       /* Adjusted size of the device internal TX buffer. */
-       u16 tx_devq_size;
-       /* Used octets of the device internal TX buffer. */
-       u16 tx_devq_used;
-       /* Used packet slots in the device internal TX buffer. */
-       u8 tx_devq_packets;
-       /* Packets from the txfree list can
-        * be taken on incoming TX requests.
-        */
-       struct list_head txfree;
-       unsigned int nr_txfree;
-       /* Packets on the txqueue are queued,
-        * but not completely written to the chip, yet.
-        */
-       struct list_head txqueue;
-       /* Packets on the txrunning queue are completely
-        * posted to the device. We are waiting for the txstatus.
-        */
-       struct list_head txrunning;
-       /* Total number or packets sent.
-        * (This counter can obviously wrap).
-        */
-       unsigned int nr_tx_packets;
-       struct tasklet_struct txtask;
-       struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
-};
-
-static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
-{
-       return b43_read16(queue->dev, queue->mmio_base + offset);
-}
-
-static inline
-    void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
-{
-       b43_write16(queue->dev, queue->mmio_base + offset, value);
-       mmiowb();
-}
-
-int b43_pio_init(struct b43_wldev *dev);
-void b43_pio_free(struct b43_wldev *dev);
-
-int b43_pio_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl);
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-                            const struct b43_txstatus *status);
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-                         struct ieee80211_tx_queue_stats *stats);
-void b43_pio_rx(struct b43_pioqueue *queue);
-
-/* Suspend TX queue in hardware. */
-void b43_pio_tx_suspend(struct b43_pioqueue *queue);
-void b43_pio_tx_resume(struct b43_pioqueue *queue);
-/* Suspend (freeze) the TX tasklet (software level). */
-void b43_pio_freeze_txqueues(struct b43_wldev *dev);
-void b43_pio_thaw_txqueues(struct b43_wldev *dev);
-
-#else /* CONFIG_B43_PIO */
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
-       return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_pio_tx(struct b43_wldev *dev,
-                  struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-       return 0;
-}
-static inline
-    void b43_pio_handle_txstatus(struct b43_wldev *dev,
-                                const struct b43_txstatus *status)
-{
-}
-static inline
-    void b43_pio_get_tx_stats(struct b43_wldev *dev,
-                             struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
-#endif /* B43_PIO_H_ */
index 800e0a61a7f589f1f649b7f6417cf6488267f4d5..11f53cb1139ee58b3686dacf8e4f1ef24cc4d00c 100644 (file)
@@ -25,6 +25,8 @@
 #include "rfkill.h"
 #include "b43.h"
 
+#include <linux/kmod.h>
+
 
 /* Returns TRUE, if the radio is enabled in hardware. */
 static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
@@ -47,32 +49,44 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
        struct b43_wldev *dev = poll_dev->private;
        struct b43_wl *wl = dev->wl;
        bool enabled;
+       bool report_change = 0;
 
        mutex_lock(&wl->mutex);
-       B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+       if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
+               mutex_unlock(&wl->mutex);
+               return;
+       }
        enabled = b43_is_hw_radio_enabled(dev);
        if (unlikely(enabled != dev->radio_hw_enable)) {
                dev->radio_hw_enable = enabled;
+               report_change = 1;
                b43info(wl, "Radio hardware status changed to %s\n",
                        enabled ? "ENABLED" : "DISABLED");
-               mutex_unlock(&wl->mutex);
-               input_report_key(poll_dev->input, KEY_WLAN, enabled);
-       } else
-               mutex_unlock(&wl->mutex);
+       }
+       mutex_unlock(&wl->mutex);
+
+       /* send the radio switch event to the system - note both a key press
+        * and a release are required */
+       if (unlikely(report_change)) {
+               input_report_key(poll_dev->input, KEY_WLAN, 1);
+               input_report_key(poll_dev->input, KEY_WLAN, 0);
+       }
 }
 
-/* Called when the RFKILL toggled in software.
- * This is called without locking. */
+/* Called when the RFKILL toggled in software. */
 static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
 {
        struct b43_wldev *dev = data;
        struct b43_wl *wl = dev->wl;
-       int err = 0;
+       int err = -EBUSY;
+
+       if (!wl->rfkill.registered)
+               return 0;
 
        mutex_lock(&wl->mutex);
        if (b43_status(dev) < B43_STAT_INITIALIZED)
                goto out_unlock;
-
+       err = 0;
        switch (state) {
        case RFKILL_STATE_ON:
                if (!dev->radio_hw_enable) {
@@ -89,7 +103,6 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
                        b43_radio_turn_off(dev, 0);
                break;
        }
-
 out_unlock:
        mutex_unlock(&wl->mutex);
 
@@ -98,11 +111,11 @@ out_unlock:
 
 char * b43_rfkill_led_name(struct b43_wldev *dev)
 {
-       struct b43_wl *wl = dev->wl;
+       struct b43_rfkill *rfk = &(dev->wl->rfkill);
 
-       if (!wl->rfkill.rfkill)
+       if (!rfk->registered)
                return NULL;
-       return rfkill_get_led_name(wl->rfkill.rfkill);
+       return rfkill_get_led_name(rfk->rfkill);
 }
 
 void b43_rfkill_init(struct b43_wldev *dev)
@@ -111,53 +124,13 @@ void b43_rfkill_init(struct b43_wldev *dev)
        struct b43_rfkill *rfk = &(wl->rfkill);
        int err;
 
-       if (rfk->rfkill) {
-               err = rfkill_register(rfk->rfkill);
-               if (err) {
-                       b43warn(wl, "Failed to register RF-kill button\n");
-                       goto err_free_rfk;
-               }
-       }
-       if (rfk->poll_dev) {
-               err = input_register_polled_device(rfk->poll_dev);
-               if (err) {
-                       b43warn(wl, "Failed to register RF-kill polldev\n");
-                       goto err_free_polldev;
-               }
-       }
-
-       return;
-err_free_rfk:
-       rfkill_free(rfk->rfkill);
-       rfk->rfkill = NULL;
-err_free_polldev:
-       input_free_polled_device(rfk->poll_dev);
-       rfk->poll_dev = NULL;
-}
-
-void b43_rfkill_exit(struct b43_wldev *dev)
-{
-       struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
-       if (rfk->poll_dev)
-               input_unregister_polled_device(rfk->poll_dev);
-       if (rfk->rfkill)
-               rfkill_unregister(rfk->rfkill);
-}
-
-void b43_rfkill_alloc(struct b43_wldev *dev)
-{
-       struct b43_wl *wl = dev->wl;
-       struct b43_rfkill *rfk = &(wl->rfkill);
+       rfk->registered = 0;
 
+       rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+       if (!rfk->rfkill)
+               goto out_error;
        snprintf(rfk->name, sizeof(rfk->name),
                 "b43-%s", wiphy_name(wl->hw->wiphy));
-
-       rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
-       if (!rfk->rfkill) {
-               b43warn(wl, "Failed to allocate RF-kill button\n");
-               return;
-       }
        rfk->rfkill->name = rfk->name;
        rfk->rfkill->state = RFKILL_STATE_ON;
        rfk->rfkill->data = dev;
@@ -165,20 +138,64 @@ void b43_rfkill_alloc(struct b43_wldev *dev)
        rfk->rfkill->user_claim_unsupported = 1;
 
        rfk->poll_dev = input_allocate_polled_device();
-       if (rfk->poll_dev) {
-               rfk->poll_dev->private = dev;
-               rfk->poll_dev->poll = b43_rfkill_poll;
-               rfk->poll_dev->poll_interval = 1000; /* msecs */
-       } else
-               b43warn(wl, "Failed to allocate RF-kill polldev\n");
+       if (!rfk->poll_dev) {
+               rfkill_free(rfk->rfkill);
+               goto err_freed_rfk;
+       }
+
+       rfk->poll_dev->private = dev;
+       rfk->poll_dev->poll = b43_rfkill_poll;
+       rfk->poll_dev->poll_interval = 1000; /* msecs */
+
+       rfk->poll_dev->input->name = rfk->name;
+       rfk->poll_dev->input->id.bustype = BUS_HOST;
+       rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
+       rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
+       set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
+
+       err = rfkill_register(rfk->rfkill);
+       if (err)
+               goto err_free_polldev;
+
+#ifdef CONFIG_RFKILL_INPUT_MODULE
+       /* B43 RF-kill isn't useful without the rfkill-input subsystem.
+        * Try to load the module. */
+       err = request_module("rfkill-input");
+       if (err)
+               b43warn(wl, "Failed to load the rfkill-input module. "
+                       "The built-in radio LED will not work.\n");
+#endif /* CONFIG_RFKILL_INPUT */
+
+       err = input_register_polled_device(rfk->poll_dev);
+       if (err)
+               goto err_unreg_rfk;
+
+       rfk->registered = 1;
+
+       return;
+err_unreg_rfk:
+       rfkill_unregister(rfk->rfkill);
+err_free_polldev:
+       input_free_polled_device(rfk->poll_dev);
+       rfk->poll_dev = NULL;
+err_freed_rfk:
+       rfk->rfkill = NULL;
+out_error:
+       rfk->registered = 0;
+       b43warn(wl, "RF-kill button init failed\n");
 }
 
-void b43_rfkill_free(struct b43_wldev *dev)
+void b43_rfkill_exit(struct b43_wldev *dev)
 {
        struct b43_rfkill *rfk = &(dev->wl->rfkill);
 
+       if (!rfk->registered)
+               return;
+       rfk->registered = 0;
+
+       input_unregister_polled_device(rfk->poll_dev);
+       rfkill_unregister(rfk->rfkill);
        input_free_polled_device(rfk->poll_dev);
        rfk->poll_dev = NULL;
-       rfkill_free(rfk->rfkill);
        rfk->rfkill = NULL;
 }
index 29544e8c9e5f41e45878fda6d80941aaa264f0dd..adacf936d815be2170b973da1cbb997fff7b974b 100644 (file)
@@ -15,14 +15,14 @@ struct b43_rfkill {
        struct rfkill *rfkill;
        /* The poll device for the RFKILL input button */
        struct input_polled_dev *poll_dev;
+       /* Did initialization succeed? Used for freeing. */
+       bool registered;
        /* The unique name of this rfkill switch */
-       char name[32];
+       char name[sizeof("b43-phy4294967295")];
 };
 
-/* All the init functions return void, because we are not interested
+/* The init function returns void, because we are not interested
  * in failing the b43 init process when rfkill init failed. */
-void b43_rfkill_alloc(struct b43_wldev *dev);
-void b43_rfkill_free(struct b43_wldev *dev);
 void b43_rfkill_init(struct b43_wldev *dev);
 void b43_rfkill_exit(struct b43_wldev *dev);
 
@@ -36,12 +36,6 @@ struct b43_rfkill {
        /* empty */
 };
 
-static inline void b43_rfkill_alloc(struct b43_wldev *dev)
-{
-}
-static inline void b43_rfkill_free(struct b43_wldev *dev)
-{
-}
 static inline void b43_rfkill_init(struct b43_wldev *dev)
 {
 }
index f4faff6a7d6c43e4a862988edf914ecbc44ce3cd..275095b8cbe743c85b5fcd0ef7499e336545d3bf 100644 (file)
@@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count)
        return ret;
 }
 
-static int get_boolean(const char *buf, size_t count)
-{
-       if (count != 0) {
-               if (buf[0] == '1')
-                       return 1;
-               if (buf[0] == '0')
-                       return 0;
-               if (count >= 4 && memcmp(buf, "true", 4) == 0)
-                       return 1;
-               if (count >= 5 && memcmp(buf, "false", 5) == 0)
-                       return 0;
-               if (count >= 3 && memcmp(buf, "yes", 3) == 0)
-                       return 1;
-               if (count >= 2 && memcmp(buf, "no", 2) == 0)
-                       return 0;
-               if (count >= 2 && memcmp(buf, "on", 2) == 0)
-                       return 1;
-               if (count >= 3 && memcmp(buf, "off", 3) == 0)
-                       return 0;
-       }
-       return -EINVAL;
-}
-
 static ssize_t b43_attr_interfmode_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
 static DEVICE_ATTR(interference, 0644,
                   b43_attr_interfmode_show, b43_attr_interfmode_store);
 
-static ssize_t b43_attr_preamble_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct b43_wldev *wldev = dev_to_b43_wldev(dev);
-       ssize_t count;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       mutex_lock(&wldev->wl->mutex);
-
-       if (wldev->short_preamble)
-               count =
-                   snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
-       else
-               count =
-                   snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
-
-       mutex_unlock(&wldev->wl->mutex);
-
-       return count;
-}
-
-static ssize_t b43_attr_preamble_store(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct b43_wldev *wldev = dev_to_b43_wldev(dev);
-       unsigned long flags;
-       int value;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       value = get_boolean(buf, count);
-       if (value < 0)
-               return value;
-       mutex_lock(&wldev->wl->mutex);
-       spin_lock_irqsave(&wldev->wl->irq_lock, flags);
-
-       wldev->short_preamble = !!value;
-
-       spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
-       mutex_unlock(&wldev->wl->mutex);
-
-       return count;
-}
-
-static DEVICE_ATTR(shortpreamble, 0644,
-                  b43_attr_preamble_show, b43_attr_preamble_store);
-
 int b43_sysfs_register(struct b43_wldev *wldev)
 {
        struct device *dev = wldev->dev->dev;
-       int err;
 
        B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
 
-       err = device_create_file(dev, &dev_attr_interference);
-       if (err)
-               goto out;
-       err = device_create_file(dev, &dev_attr_shortpreamble);
-       if (err)
-               goto err_remove_interfmode;
-
-      out:
-       return err;
-      err_remove_interfmode:
-       device_remove_file(dev, &dev_attr_interference);
-       goto out;
+       return device_create_file(dev, &dev_attr_interference);
 }
 
 void b43_sysfs_unregister(struct b43_wldev *wldev)
 {
        struct device *dev = wldev->dev->dev;
 
-       device_remove_file(dev, &dev_attr_shortpreamble);
        device_remove_file(dev, &dev_attr_interference);
 }
index 15a87183a572612b68b39169b3ac85278d35426b..3f5ea06bf13cb0ea5c20d4ba2b6899a3d48e5b10 100644 (file)
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = {
 };
 
 const u16 b43_tab_noisea3[] = {
-       0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+       0x5E5E, 0x5E5E, 0x5E5E, 0x3F48,
        0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
 };
 
@@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = {
        0x0000, 0x0000, 0x0000, 0x0000,
 };
 
+const u16 b43_tab_noisescalea2[] = {
+       0x6767, 0x6767, 0x6767, 0x6767, /* 0 */
+       0x6767, 0x6767, 0x6767, 0x6767,
+       0x6767, 0x6767, 0x6767, 0x6767,
+       0x6767, 0x6700, 0x6767, 0x6767,
+       0x6767, 0x6767, 0x6767, 0x6767, /* 16 */
+       0x6767, 0x6767, 0x6767, 0x6767,
+       0x6767, 0x6767, 0x0067,
+};
+
+const u16 b43_tab_noisescalea3[] = {
+       0x2323, 0x2323, 0x2323, 0x2323, /* 0 */
+       0x2323, 0x2323, 0x2323, 0x2323,
+       0x2323, 0x2323, 0x2323, 0x2323,
+       0x2323, 0x2300, 0x2323, 0x2323,
+       0x2323, 0x2323, 0x2323, 0x2323, /* 16 */
+       0x2323, 0x2323, 0x2323, 0x2323,
+       0x2323, 0x2323, 0x0023,
+};
+
 const u16 b43_tab_noisescaleg1[] = {
        0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
        0x2F2D, 0x2A2A, 0x2527, 0x1F21,
@@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = {
 };
 
 const u16 b43_tab_noisescaleg2[] = {
-       0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+       0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7, /* 0 */
        0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
        0x969B, 0x9195, 0x8F8F, 0x8A8A,
        0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
@@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = {
        0x00DE,
 };
 
+const u16 b43_tab_rssiagc1[] = {
+       0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */
+       0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE,
+       0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+       0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+};
+
+const u16 b43_tab_rssiagc2[] = {
+       0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */
+       0x0820, 0x0820, 0x0820, 0x0820,
+       0x0820, 0x0820, 0x0920, 0x0A38,
+       0x0820, 0x0820, 0x0820, 0x0820,
+       0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */
+       0x0820, 0x0820, 0x0820, 0x0820,
+       0x0820, 0x0820, 0x0920, 0x0A38,
+       0x0820, 0x0820, 0x0820, 0x0820,
+       0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */
+       0x0820, 0x0820, 0x0820, 0x0820,
+       0x0820, 0x0820, 0x0920, 0x0A38,
+       0x0820, 0x0820, 0x0820, 0x0820,
+};
+
 static inline void assert_sizes(void)
 {
        BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
@@ -317,36 +359,73 @@ static inline void assert_sizes(void)
        BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
        BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
        BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
-       BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+       BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+                    ARRAY_SIZE(b43_tab_noisescalea2));
+       BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+                    ARRAY_SIZE(b43_tab_noisescalea3));
+       BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
                     ARRAY_SIZE(b43_tab_noisescaleg1));
-       BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+       BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
                     ARRAY_SIZE(b43_tab_noisescaleg2));
-       BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+       BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
                     ARRAY_SIZE(b43_tab_noisescaleg3));
        BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
        BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+       BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1));
+       BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2));
 }
 
 u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
 {
-       assert_sizes();
+       struct b43_phy *phy = &dev->phy;
+       u16 addr;
+
+       addr = table + offset;
+       if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+           (addr - 1 != phy->ofdmtab_addr)) {
+               /* The hardware has a different address in memory. Update it. */
+               b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+               phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+       }
+       phy->ofdmtab_addr = addr;
 
-       b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
        return b43_phy_read(dev, B43_PHY_OTABLEI);
+
+       /* Some compiletime assertions... */
+       assert_sizes();
 }
 
 void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
                         u16 offset, u16 value)
 {
-       b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+       struct b43_phy *phy = &dev->phy;
+       u16 addr;
+
+       addr = table + offset;
+       if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+           (addr - 1 != phy->ofdmtab_addr)) {
+               /* The hardware has a different address in memory. Update it. */
+               b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+               phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+       }
+       phy->ofdmtab_addr = addr;
        b43_phy_write(dev, B43_PHY_OTABLEI, value);
 }
 
 u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 {
+       struct b43_phy *phy = &dev->phy;
        u32 ret;
+       u16 addr;
 
-       b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+       addr = table + offset;
+       if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+           (addr - 1 != phy->ofdmtab_addr)) {
+               /* The hardware has a different address in memory. Update it. */
+               b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+               phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+       }
+       phy->ofdmtab_addr = addr;
        ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
        ret <<= 16;
        ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
                         u16 offset, u32 value)
 {
-       b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+       struct b43_phy *phy = &dev->phy;
+       u16 addr;
+
+       addr = table + offset;
+       if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+           (addr - 1 != phy->ofdmtab_addr)) {
+               /* The hardware has a different address in memory. Update it. */
+               b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+               phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+       }
+       phy->ofdmtab_addr = addr;
+
        b43_phy_write(dev, B43_PHY_OTABLEI, value);
        b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
 }
index 64635d7b518c3e9500d08193fc2190ecaa44a407..80e73c7cbac5695c4b1620a9f729d4ca652dad37 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef B43_TABLES_H_
 #define B43_TABLES_H_
 
-#define B43_TAB_ROTOR_SIZE             53
+#define B43_TAB_ROTOR_SIZE     53
 extern const u32 b43_tab_rotor[];
-#define B43_TAB_RETARD_SIZE            53
+#define B43_TAB_RETARD_SIZE    53
 extern const u32 b43_tab_retard[];
 #define B43_TAB_FINEFREQA_SIZE 256
 extern const u16 b43_tab_finefreqa[];
@@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[];
 extern const u16 b43_tab_noiseg1[];
 #define B43_TAB_NOISEG2_SIZE   8
 extern const u16 b43_tab_noiseg2[];
-#define B43_TAB_NOISESCALEG_SIZE       27
+#define B43_TAB_NOISESCALE_SIZE        27
+extern const u16 b43_tab_noisescalea2[];
+extern const u16 b43_tab_noisescalea3[];
 extern const u16 b43_tab_noisescaleg1[];
 extern const u16 b43_tab_noisescaleg2[];
 extern const u16 b43_tab_noisescaleg3[];
 #define B43_TAB_SIGMASQR_SIZE  53
 extern const u16 b43_tab_sigmasqr1[];
 extern const u16 b43_tab_sigmasqr2[];
+#define B43_TAB_RSSIAGC1_SIZE  16
+extern const u16 b43_tab_rssiagc1[];
+#define B43_TAB_RSSIAGC2_SIZE  48
+extern const u16 b43_tab_rssiagc2[];
 
 #endif /* B43_TABLES_H_ */
diff --git a/package/b43/src/tables_nphy.c b/package/b43/src/tables_nphy.c
new file mode 100644 (file)
index 0000000..2aa5755
--- /dev/null
@@ -0,0 +1,2476 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY and radio device data tables
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables_nphy.h"
+#include "phy.h"
+#include "nphy.h"
+
+
+struct b2055_inittab_entry {
+       /* Value to write if we use the 5GHz band. */
+       u16 ghz5;
+       /* Value to write if we use the 2.4GHz band. */
+       u16 ghz2;
+       /* Flags */
+       u8 flags;
+#define B2055_INITTAB_ENTRY_OK 0x01
+#define B2055_INITTAB_UPLOAD   0x02
+};
+#define UPLOAD         .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD
+#define NOUPLOAD       .flags = B2055_INITTAB_ENTRY_OK
+
+static const struct b2055_inittab_entry b2055_inittab [] = {
+  [B2055_SP_PINPD]             = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_SP_RSSI]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_SP_PDMISC]         = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C2_SP_RSSI]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_SP_PDMISC]         = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C1_SP_RXGC1]          = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C1_SP_RXGC2]          = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C2_SP_RXGC1]          = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C2_SP_RXGC2]          = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C1_SP_LPFBWSEL]       = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_SP_LPFBWSEL]       = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_SP_TXGC1]          = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C1_SP_TXGC2]          = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_C2_SP_TXGC1]          = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C2_SP_TXGC2]          = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_MASTER1]              = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, },
+  [B2055_MASTER2]              = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_PD_LGEN]              = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PD_PLLTS]             = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+  [B2055_C1_PD_LGBUF]          = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_TX]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RXTX]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RSSIMISC]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_LGBUF]          = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_TX]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RXTX]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RSSIMISC]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PWRDET_LGEN]          = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C1_PWRDET_LGBUF]      = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C1_PWRDET_RXTX]       = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C2_PWRDET_LGBUF]      = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C2_PWRDET_RXTX]       = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_RRCCAL_CS]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_RRCCAL_NOPTSEL]       = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, },
+  [B2055_CAL_MISC]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT2]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_CVARCTL]          = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RVARCTL]          = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_LPOCTL]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_TS]               = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCCALRTS]         = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCALRTS]          = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PADDRV]               = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_XOCTL1]               = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+  [B2055_XOCTL2]               = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_XOREGUL]              = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_XOMISC]               = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PLL_LFC1]             = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_PLL_CALVTH]           = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, },
+  [B2055_PLL_LFC2]             = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_PLL_REF]              = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+  [B2055_PLL_LFR1]             = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+  [B2055_PLL_PFDCP]            = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, },
+  [B2055_PLL_IDAC_CPOPAMP]     = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_PLL_CPREG]            = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_PLL_RCAL]             = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_RF_PLLMOD0]           = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, },
+  [B2055_RF_PLLMOD1]           = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_RF_MMDIDAC1]          = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, },
+  [B2055_RF_MMDIDAC0]          = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_RF_MMDSP]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL1]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL2]             = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL3]             = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+  [B2055_VCO_CAL4]             = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL5]             = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+  [B2055_VCO_CAL6]             = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL7]             = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL8]             = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+  [B2055_VCO_CAL9]             = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL10]            = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_VCO_CAL11]            = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_VCO_CAL12]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL13]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL14]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL15]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL16]            = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_KVCO]             = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_CAPTAIL]          = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_IDACVCO]          = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_VCO_REG]              = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, },
+  [B2055_PLL_RFVTH]            = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, },
+  [B2055_LGBUF_CENBUF]         = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, },
+  [B2055_LGEN_TUNE1]           = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_TUNE2]           = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_IDAC1]           = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_IDAC2]           = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_BIASC]           = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_LGEN_BIASIDAC]                = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, },
+  [B2055_LGEN_RCAL]            = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_LGEN_DIV]             = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_LGEN_SPARE2]          = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_LGBUF_ATUNE]       = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C1_LGBUF_GTUNE]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_DIV]         = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_AIDAC]       = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C1_LGBUF_GIDAC]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_IDACFO]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LGBUF_SPARE]       = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C1_RX_RFSPC1]         = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C1_RX_RFR1]           = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_RX_RFR2]           = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C1_RX_RFRCAL]         = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_RX_BB_BLCMP]       = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C1_RX_BB_LPF]         = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_RX_BB_MIDACHP]     = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_VGA1IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA2IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA3IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_BUFOCTL]     = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_RCCALCTL]    = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL1]    = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL2]    = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL3]    = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL4]    = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL5]    = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C1_RX_BB_REG]         = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_SPARE1]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_RX_TXBBRCAL]       = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPGA]                = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPAD]                = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPGA1]     = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPAD1]     = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C1_TX_RF_PGAIDAC]     = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C1_TX_PGAPADTN]       = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_TX_PADIDAC1]       = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C1_TX_PADIDAC2]       = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C1_TX_MXBGTRIM]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_TX_RF_RCAL]                = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI1]    = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI2]    = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPARE]       = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_IQCAL1]      = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_TX_RF_IQCAL2]      = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C1_TXBB_RCCAL]                = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_TXBB_LPF1]         = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C1_TX_VOSCNCL]                = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_TX_LPF_MXGMIDAC]   = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C1_TX_BB_MXGM]                = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_ATUNE]       = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C2_LGBUF_GTUNE]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_DIV]         = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_AIDAC]       = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C2_LGBUF_GIDAC]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_IDACFO]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_SPARE]       = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C2_RX_RFSPC1]         = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C2_RX_RFR1]           = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_RX_RFR2]           = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C2_RX_RFRCAL]         = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_RX_BB_BLCMP]       = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C2_RX_BB_LPF]         = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_RX_BB_MIDACHP]     = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_VGA1IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA2IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA3IDAC]    = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_BUFOCTL]     = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_RCCALCTL]    = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL1]    = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL2]    = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL3]    = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL4]    = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL5]    = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C2_RX_BB_REG]         = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_SPARE1]      = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_RX_TXBBRCAL]       = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPGA]                = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPAD]                = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPGA1]     = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPAD1]     = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C2_TX_RF_PGAIDAC]     = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C2_TX_PGAPADTN]       = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_TX_PADIDAC1]       = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C2_TX_PADIDAC2]       = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C2_TX_MXBGTRIM]       = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_TX_RF_RCAL]                = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI1]    = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI2]    = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPARE]       = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_IQCAL1]      = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_TX_RF_IQCAL2]      = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C2_TXBB_RCCAL]                = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_TXBB_LPF1]         = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C2_TX_VOSCNCL]                = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_TX_LPF_MXGMIDAC]   = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C2_TX_BB_MXGM]                = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PRG_GCHP21]           = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, },
+  [B2055_PRG_GCHP22]           = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, },
+  [B2055_PRG_GCHP23]           = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, },
+  [B2055_PRG_GCHP24]           = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, },
+  [B2055_PRG_GCHP25]           = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, },
+  [B2055_PRG_GCHP26]           = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, },
+  [B2055_PRG_GCHP27]           = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+  [B2055_PRG_GCHP28]           = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, },
+  [B2055_PRG_GCHP29]           = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, },
+  [B2055_PRG_GCHP30]           = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, },
+  [0xC7]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC8]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC9]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCA]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCB]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCC]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LNA_GAINBST]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCE]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCF]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD0]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD1]                       = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_B0NB_RSSIVCM]      = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xD3]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD4]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD5]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_GENSPARE2]         = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD7]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD8]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LNA_GAINBST]       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDA]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDB]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDC]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDD]                       = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_B0NB_RSSIVCM]      = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xDF]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE0]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE1]                       = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_GENSPARE2]         = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+
+void b2055_upload_inittab(struct b43_wldev *dev,
+                         bool ghz5, bool ignore_uploadflag)
+{
+       const struct b2055_inittab_entry *e;
+       unsigned int i;
+       u16 value;
+
+       for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
+               e = &(b2055_inittab[i]);
+               if (!(e->flags & B2055_INITTAB_ENTRY_OK))
+                       continue;
+               if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) {
+                       if (ghz5)
+                               value = e->ghz5;
+                       else
+                               value = e->ghz2;
+                       b43_radio_write16(dev, i, value);
+               }
+       }
+}
+
+
+#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \
+                 r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \
+       .radio_pll_ref          = r0,   \
+       .radio_rf_pllmod0       = r1,   \
+       .radio_rf_pllmod1       = r2,   \
+       .radio_vco_captail      = r3,   \
+       .radio_vco_cal1         = r4,   \
+       .radio_vco_cal2         = r5,   \
+       .radio_pll_lfc1         = r6,   \
+       .radio_pll_lfr1         = r7,   \
+       .radio_pll_lfc2         = r8,   \
+       .radio_lgbuf_cenbuf     = r9,   \
+       .radio_lgen_tune1       = r10,  \
+       .radio_lgen_tune2       = r11,  \
+       .radio_c1_lgbuf_atune   = r12,  \
+       .radio_c1_lgbuf_gtune   = r13,  \
+       .radio_c1_rx_rfr1       = r14,  \
+       .radio_c1_tx_pgapadtn   = r15,  \
+       .radio_c1_tx_mxbgtrim   = r16,  \
+       .radio_c2_lgbuf_atune   = r17,  \
+       .radio_c2_lgbuf_gtune   = r18,  \
+       .radio_c2_rx_rfr1       = r19,  \
+       .radio_c2_tx_pgapadtn   = r20,  \
+       .radio_c2_tx_mxbgtrim   = r21
+
+#define PHYREGS(r0, r1, r2, r3, r4, r5)        \
+       .phy_bw1a       = r0,           \
+       .phy_bw2        = r1,           \
+       .phy_bw3        = r2,           \
+       .phy_bw4        = r3,           \
+       .phy_bw5        = r4,           \
+       .phy_bw6        = r5
+
+static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
+  {    .channel                = 184,
+       .freq                   = 4920, /* MHz */
+       .unk2                   = 3280,
+       RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
+  },
+  {    .channel                = 186,
+       .freq                   = 4930, /* MHz */
+       .unk2                   = 3287,
+       RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
+  },
+  {    .channel                = 188,
+       .freq                   = 4940, /* MHz */
+       .unk2                   = 3293,
+       RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
+  },
+  {    .channel                = 190,
+       .freq                   = 4950, /* MHz */
+       .unk2                   = 3300,
+       RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
+  },
+  {    .channel                = 192,
+       .freq                   = 4960, /* MHz */
+       .unk2                   = 3307,
+       RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
+  },
+  {    .channel                = 194,
+       .freq                   = 4970, /* MHz */
+       .unk2                   = 3313,
+       RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
+  },
+  {    .channel                = 196,
+       .freq                   = 4980, /* MHz */
+       .unk2                   = 3320,
+       RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
+  },
+  {    .channel                = 198,
+       .freq                   = 4990, /* MHz */
+       .unk2                   = 3327,
+       RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
+  },
+  {    .channel                = 200,
+       .freq                   = 5000, /* MHz */
+       .unk2                   = 3333,
+       RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
+  },
+  {    .channel                = 202,
+       .freq                   = 5010, /* MHz */
+       .unk2                   = 3340,
+       RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
+  },
+  {    .channel                = 204,
+       .freq                   = 5020, /* MHz */
+       .unk2                   = 3347,
+       RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
+  },
+  {    .channel                = 206,
+       .freq                   = 5030, /* MHz */
+       .unk2                   = 3353,
+       RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
+  },
+  {    .channel                = 208,
+       .freq                   = 5040, /* MHz */
+       .unk2                   = 3360,
+       RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
+  },
+  {    .channel                = 210,
+       .freq                   = 5050, /* MHz */
+       .unk2                   = 3367,
+       RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+                 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+       PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
+  },
+  {    .channel                = 212,
+       .freq                   = 5060, /* MHz */
+       .unk2                   = 3373,
+       RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+                 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+       PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
+  },
+  {    .channel                = 214,
+       .freq                   = 5070, /* MHz */
+       .unk2                   = 3380,
+       RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+                 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+       PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
+  },
+  {    .channel                = 216,
+       .freq                   = 5080, /* MHz */
+       .unk2                   = 3387,
+       RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+                 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+       PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
+  },
+  {    .channel                = 218,
+       .freq                   = 5090, /* MHz */
+       .unk2                   = 3393,
+       RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+                 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+       PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
+  },
+  {    .channel                = 220,
+       .freq                   = 5100, /* MHz */
+       .unk2                   = 3400,
+       RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+                 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+       PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
+  },
+  {    .channel                = 222,
+       .freq                   = 5110, /* MHz */
+       .unk2                   = 3407,
+       RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+                 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+       PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
+  },
+  {    .channel                = 224,
+       .freq                   = 5120, /* MHz */
+       .unk2                   = 3413,
+       RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+                 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+       PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
+  },
+  {    .channel                = 226,
+       .freq                   = 5130, /* MHz */
+       .unk2                   = 3420,
+       RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+                 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+       PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
+  },
+  {    .channel                = 228,
+       .freq                   = 5140, /* MHz */
+       .unk2                   = 3427,
+       RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
+                 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
+       PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
+  },
+  {    .channel                = 32,
+       .freq                   = 5160, /* MHz */
+       .unk2                   = 3440,
+       RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+                 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+       PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
+  },
+  {    .channel                = 34,
+       .freq                   = 5170, /* MHz */
+       .unk2                   = 3447,
+       RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+                 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+                 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+       PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
+  },
+  {    .channel                = 36,
+       .freq                   = 5180, /* MHz */
+       .unk2                   = 3453,
+       RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+                 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+       PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
+  },
+  {    .channel                = 38,
+       .freq                   = 5190, /* MHz */
+       .unk2                   = 3460,
+       RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+                 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+                 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+       PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
+  },
+  {    .channel                = 40,
+       .freq                   = 5200, /* MHz */
+       .unk2                   = 3467,
+       RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+                 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+       PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
+  },
+  {    .channel                = 42,
+       .freq                   = 5210, /* MHz */
+       .unk2                   = 3473,
+       RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+                 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+                 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+       PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
+  },
+  {    .channel                = 44,
+       .freq                   = 5220, /* MHz */
+       .unk2                   = 3480,
+       RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+                 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+                 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+       PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
+  },
+  {    .channel                = 46,
+       .freq                   = 5230, /* MHz */
+       .unk2                   = 3487,
+       RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+                 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+                 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+       PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
+  },
+  {    .channel                = 48,
+       .freq                   = 5240, /* MHz */
+       .unk2                   = 3493,
+       RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+                 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+                 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+       PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
+  },
+  {    .channel                = 50,
+       .freq                   = 5250, /* MHz */
+       .unk2                   = 3500,
+       RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+                 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+                 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+       PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
+  },
+  {    .channel                = 52,
+       .freq                   = 5260, /* MHz */
+       .unk2                   = 3507,
+       RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+                 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+                 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+       PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
+  },
+  {    .channel                = 54,
+       .freq                   = 5270, /* MHz */
+       .unk2                   = 3513,
+       RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+                 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+                 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+       PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
+  },
+  {    .channel                = 56,
+       .freq                   = 5280, /* MHz */
+       .unk2                   = 3520,
+       RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+                 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+                 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+       PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
+  },
+  {    .channel                = 58,
+       .freq                   = 5290, /* MHz */
+       .unk2                   = 3527,
+       RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+                 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+                 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+       PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
+  },
+  {    .channel                = 60,
+       .freq                   = 5300, /* MHz */
+       .unk2                   = 3533,
+       RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+                 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+                 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+       PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
+  },
+  {    .channel                = 62,
+       .freq                   = 5310, /* MHz */
+       .unk2                   = 3540,
+       RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+                 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+                 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+       PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
+  },
+  {    .channel                = 64,
+       .freq                   = 5320, /* MHz */
+       .unk2                   = 3547,
+       RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+                 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+                 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+       PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
+  },
+  {    .channel                = 66,
+       .freq                   = 5330, /* MHz */
+       .unk2                   = 3553,
+       RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+                 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+                 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+       PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
+  },
+  {    .channel                = 68,
+       .freq                   = 5340, /* MHz */
+       .unk2                   = 3560,
+       RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+                 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+                 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+       PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
+  },
+  {    .channel                = 70,
+       .freq                   = 5350, /* MHz */
+       .unk2                   = 3567,
+       RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+                 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+                 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+       PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
+  },
+  {    .channel                = 72,
+       .freq                   = 5360, /* MHz */
+       .unk2                   = 3573,
+       RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+                 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+                 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+       PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
+  },
+  {    .channel                = 74,
+       .freq                   = 5370, /* MHz */
+       .unk2                   = 3580,
+       RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+                 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+                 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+       PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
+  },
+  {    .channel                = 76,
+       .freq                   = 5380, /* MHz */
+       .unk2                   = 3587,
+       RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+                 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+                 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+       PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
+  },
+  {    .channel                = 78,
+       .freq                   = 5390, /* MHz */
+       .unk2                   = 3593,
+       RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+                 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+                 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+       PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
+  },
+  {    .channel                = 80,
+       .freq                   = 5400, /* MHz */
+       .unk2                   = 3600,
+       RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+                 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+                 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+       PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
+  },
+  {    .channel                = 82,
+       .freq                   = 5410, /* MHz */
+       .unk2                   = 3607,
+       RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+                 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+                 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+       PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
+  },
+  {    .channel                = 84,
+       .freq                   = 5420, /* MHz */
+       .unk2                   = 3613,
+       RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+                 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+                 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+       PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
+  },
+  {    .channel                = 86,
+       .freq                   = 5430, /* MHz */
+       .unk2                   = 3620,
+       RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+                 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+                 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+       PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
+  },
+  {    .channel                = 88,
+       .freq                   = 5440, /* MHz */
+       .unk2                   = 3627,
+       RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+                 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+                 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+       PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
+  },
+  {    .channel                = 90,
+       .freq                   = 5450, /* MHz */
+       .unk2                   = 3633,
+       RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+                 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+                 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+       PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
+  },
+  {    .channel                = 92,
+       .freq                   = 5460, /* MHz */
+       .unk2                   = 3640,
+       RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+                 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+                 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+       PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
+  },
+  {    .channel                = 94,
+       .freq                   = 5470, /* MHz */
+       .unk2                   = 3647,
+       RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+                 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+                 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+       PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
+  },
+  {    .channel                = 96,
+       .freq                   = 5480, /* MHz */
+       .unk2                   = 3653,
+       RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+                 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+                 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+       PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
+  },
+  {    .channel                = 98,
+       .freq                   = 5490, /* MHz */
+       .unk2                   = 3660,
+       RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+                 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+                 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+       PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
+  },
+  {    .channel                = 100,
+       .freq                   = 5500, /* MHz */
+       .unk2                   = 3667,
+       RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+                 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+                 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+       PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
+  },
+  {    .channel                = 102,
+       .freq                   = 5510, /* MHz */
+       .unk2                   = 3673,
+       RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+                 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+                 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+       PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
+  },
+  {    .channel                = 104,
+       .freq                   = 5520, /* MHz */
+       .unk2                   = 3680,
+       RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+                 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+                 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+       PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
+  },
+  {    .channel                = 106,
+       .freq                   = 5530, /* MHz */
+       .unk2                   = 3687,
+       RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+                 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+                 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+       PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
+  },
+  {    .channel                = 108,
+       .freq                   = 5540, /* MHz */
+       .unk2                   = 3693,
+       RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+                 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+                 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+       PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
+  },
+  {    .channel                = 110,
+       .freq                   = 5550, /* MHz */
+       .unk2                   = 3700,
+       RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+                 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+                 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+       PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
+  },
+  {    .channel                = 112,
+       .freq                   = 5560, /* MHz */
+       .unk2                   = 3707,
+       RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+                 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+                 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
+  },
+  {    .channel                = 114,
+       .freq                   = 5570, /* MHz */
+       .unk2                   = 3713,
+       RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+                 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+                 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
+  },
+  {    .channel                = 116,
+       .freq                   = 5580, /* MHz */
+       .unk2                   = 3720,
+       RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+                 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+                 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
+  },
+  {    .channel                = 118,
+       .freq                   = 5590, /* MHz */
+       .unk2                   = 3727,
+       RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+                 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+                 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
+  },
+  {    .channel                = 120,
+       .freq                   = 5600, /* MHz */
+       .unk2                   = 3733,
+       RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+                 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+                 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
+  },
+  {    .channel                = 122,
+       .freq                   = 5610, /* MHz */
+       .unk2                   = 3740,
+       RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+                 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+                 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+       PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
+  },
+  {    .channel                = 124,
+       .freq                   = 5620, /* MHz */
+       .unk2                   = 3747,
+       RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+                 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+                 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
+  },
+  {    .channel                = 126,
+       .freq                   = 5630, /* MHz */
+       .unk2                   = 3753,
+       RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+                 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+                 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
+  },
+  {    .channel                = 128,
+       .freq                   = 5640, /* MHz */
+       .unk2                   = 3760,
+       RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
+  },
+  {    .channel                = 130,
+       .freq                   = 5650, /* MHz */
+       .unk2                   = 3767,
+       RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
+  },
+  {    .channel                = 132,
+       .freq                   = 5660, /* MHz */
+       .unk2                   = 3773,
+       RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
+  },
+  {    .channel                = 134,
+       .freq                   = 5670, /* MHz */
+       .unk2                   = 3780,
+       RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
+  },
+  {    .channel                = 136,
+       .freq                   = 5680, /* MHz */
+       .unk2                   = 3787,
+       RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
+  },
+  {    .channel                = 138,
+       .freq                   = 5690, /* MHz */
+       .unk2                   = 3793,
+       RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
+  },
+  {    .channel                = 140,
+       .freq                   = 5700, /* MHz */
+       .unk2                   = 3800,
+       RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
+  },
+  {    .channel                = 142,
+       .freq                   = 5710, /* MHz */
+       .unk2                   = 3807,
+       RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
+  },
+  {    .channel                = 144,
+       .freq                   = 5720, /* MHz */
+       .unk2                   = 3813,
+       RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {    .channel                = 145,
+       .freq                   = 5725, /* MHz */
+       .unk2                   = 3817,
+       RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {    .channel                = 146,
+       .freq                   = 5730, /* MHz */
+       .unk2                   = 3820,
+       RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
+  },
+  {    .channel                = 147,
+       .freq                   = 5735, /* MHz */
+       .unk2                   = 3823,
+       RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
+  },
+  {    .channel                = 148,
+       .freq                   = 5740, /* MHz */
+       .unk2                   = 3827,
+       RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
+  },
+  {    .channel                = 149,
+       .freq                   = 5745, /* MHz */
+       .unk2                   = 3830,
+       RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
+  },
+  {    .channel                = 150,
+       .freq                   = 5750, /* MHz */
+       .unk2                   = 3833,
+       RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
+  },
+  {    .channel                = 151,
+       .freq                   = 5755, /* MHz */
+       .unk2                   = 3837,
+       RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
+  },
+  {    .channel                = 152,
+       .freq                   = 5760, /* MHz */
+       .unk2                   = 3840,
+       RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
+  },
+  {    .channel                = 153,
+       .freq                   = 5765, /* MHz */
+       .unk2                   = 3843,
+       RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
+  },
+  {    .channel                = 154,
+       .freq                   = 5770, /* MHz */
+       .unk2                   = 3847,
+       RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
+  },
+  {    .channel                = 155,
+       .freq                   = 5775, /* MHz */
+       .unk2                   = 3850,
+       RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
+  },
+  {    .channel                = 156,
+       .freq                   = 5780, /* MHz */
+       .unk2                   = 3853,
+       RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
+  },
+  {    .channel                = 157,
+       .freq                   = 5785, /* MHz */
+       .unk2                   = 3857,
+       RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
+  },
+  {    .channel                = 158,
+       .freq                   = 5790, /* MHz */
+       .unk2                   = 3860,
+       RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
+  },
+  {    .channel                = 159,
+       .freq                   = 5795, /* MHz */
+       .unk2                   = 3863,
+       RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
+  },
+  {    .channel                = 160,
+       .freq                   = 5800, /* MHz */
+       .unk2                   = 3867,
+       RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
+  },
+  {    .channel                = 161,
+       .freq                   = 5805, /* MHz */
+       .unk2                   = 3870,
+       RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
+  },
+  {    .channel                = 162,
+       .freq                   = 5810, /* MHz */
+       .unk2                   = 3873,
+       RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
+  },
+  {    .channel                = 163,
+       .freq                   = 5815, /* MHz */
+       .unk2                   = 3877,
+       RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
+  },
+  {    .channel                = 164,
+       .freq                   = 5820, /* MHz */
+       .unk2                   = 3880,
+       RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
+  },
+  {    .channel                = 165,
+       .freq                   = 5825, /* MHz */
+       .unk2                   = 3883,
+       RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
+  },
+  {    .channel                = 166,
+       .freq                   = 5830, /* MHz */
+       .unk2                   = 3887,
+       RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
+  },
+  {    .channel                = 168,
+       .freq                   = 5840, /* MHz */
+       .unk2                   = 3893,
+       RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
+  },
+  {    .channel                = 170,
+       .freq                   = 5850, /* MHz */
+       .unk2                   = 3900,
+       RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
+  },
+  {    .channel                = 172,
+       .freq                   = 5860, /* MHz */
+       .unk2                   = 3907,
+       RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
+  },
+  {    .channel                = 174,
+       .freq                   = 5870, /* MHz */
+       .unk2                   = 3913,
+       RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
+  },
+  {    .channel                = 176,
+       .freq                   = 5880, /* MHz */
+       .unk2                   = 3920,
+       RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
+  },
+  {    .channel                = 178,
+       .freq                   = 5890, /* MHz */
+       .unk2                   = 3927,
+       RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
+  },
+  {    .channel                = 180,
+       .freq                   = 5900, /* MHz */
+       .unk2                   = 3933,
+       RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
+  },
+  {    .channel                = 182,
+       .freq                   = 5910, /* MHz */
+       .unk2                   = 3940,
+       RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+                 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+       PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
+  },
+  {    .channel                = 1,
+       .freq                   = 2412, /* MHz */
+       .unk2                   = 3216,
+       RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
+                 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
+       PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
+  },
+  {    .channel                = 2,
+       .freq                   = 2417, /* MHz */
+       .unk2                   = 3223,
+       RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
+                 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
+       PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
+  },
+  {    .channel                = 3,
+       .freq                   = 2422, /* MHz */
+       .unk2                   = 3229,
+       RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+                 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+       PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
+  },
+  {    .channel                = 4,
+       .freq                   = 2427, /* MHz */
+       .unk2                   = 3236,
+       RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+                 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+       PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
+  },
+  {    .channel                = 5,
+       .freq                   = 2432, /* MHz */
+       .unk2                   = 3243,
+       RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
+                 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
+       PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
+  },
+  {    .channel                = 6,
+       .freq                   = 2437, /* MHz */
+       .unk2                   = 3249,
+       RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
+                 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
+       PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
+  },
+  {    .channel                = 7,
+       .freq                   = 2442, /* MHz */
+       .unk2                   = 3256,
+       RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
+                 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
+       PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
+  },
+  {    .channel                = 8,
+       .freq                   = 2447, /* MHz */
+       .unk2                   = 3263,
+       RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
+                 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
+       PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
+  },
+  {    .channel                = 9,
+       .freq                   = 2452, /* MHz */
+       .unk2                   = 3269,
+       RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
+                 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
+       PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
+  },
+  {    .channel                = 10,
+       .freq                   = 2457, /* MHz */
+       .unk2                   = 3276,
+       RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
+                 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
+       PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
+  },
+  {    .channel                = 11,
+       .freq                   = 2462, /* MHz */
+       .unk2                   = 3283,
+       RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
+                 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
+       PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
+  },
+  {    .channel                = 12,
+       .freq                   = 2467, /* MHz */
+       .unk2                   = 3289,
+       RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
+                 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
+       PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
+  },
+  {    .channel                = 13,
+       .freq                   = 2472, /* MHz */
+       .unk2                   = 3296,
+       RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
+                 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
+       PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
+  },
+  {    .channel                = 14,
+       .freq                   = 2484, /* MHz */
+       .unk2                   = 3312,
+       RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+                 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
+                 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
+       PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
+  },
+};
+
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
+{
+       const struct b43_nphy_channeltab_entry *e;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {
+               e = &(b43_nphy_channeltab[i]);
+               if (e->channel == channel)
+                       return e;
+       }
+
+       return NULL;
+}
+
+
+const u8 b43_ntab_adjustpower0[] = {
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+       0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+       0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+       0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+       0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+       0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+       0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+       0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+       0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+       0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+       0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+       0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+       0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+       0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+       0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u8 b43_ntab_adjustpower1[] = {
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+       0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+       0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+       0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+       0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+       0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+       0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+       0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+       0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+       0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+       0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+       0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+       0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+       0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+       0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u16 b43_ntab_bdi[] = {
+       0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
+};
+
+const u32 b43_ntab_channelest[] = {
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x44444444, 0x44444444, 0x44444444, 0x44444444,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+       0x10101010, 0x10101010, 0x10101010, 0x10101010,
+};
+
+const u8 b43_ntab_estimatepowerlt0[] = {
+       0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+       0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+       0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+       0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+       0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+       0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+       0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+       0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_estimatepowerlt1[] = {
+       0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+       0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+       0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+       0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+       0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+       0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+       0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+       0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_framelookup[] = {
+       0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
+       0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
+       0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
+       0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
+};
+
+const u32 b43_ntab_framestruct[] = {
+       0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+       0x09804506, 0x00100030, 0x09804507, 0x00100030,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+       0x0980450E, 0x00100038, 0x0980450F, 0x00100038,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+       0x1980C506, 0x00100030, 0x21810506, 0x00100030,
+       0x21810506, 0x00100030, 0x01800504, 0x00100030,
+       0x11808505, 0x00100030, 0x29814507, 0x01100030,
+       0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+       0x21810506, 0x00100030, 0x21810506, 0x00100030,
+       0x29814507, 0x01100030, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+       0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+       0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+       0x1180850D, 0x00100038, 0x2981450F, 0x01100038,
+       0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+       0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+       0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+       0x1980C506, 0x00100030, 0x1980C506, 0x00100030,
+       0x11808504, 0x00100030, 0x3981CA05, 0x00100030,
+       0x29814507, 0x01100030, 0x00000000, 0x00000000,
+       0x10008A04, 0x00100000, 0x3981CA05, 0x00100030,
+       0x1980C506, 0x00100030, 0x29814507, 0x01100030,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+       0x1980C50E, 0x00100038, 0x1980C50E, 0x00100038,
+       0x1180850C, 0x00100038, 0x3981CA0D, 0x00100038,
+       0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+       0x10008A0C, 0x00100008, 0x3981CA0D, 0x00100038,
+       0x1980C50E, 0x00100038, 0x2981450F, 0x01100038,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x40021404, 0x00100000, 0x02001405, 0x00100040,
+       0x0B004A06, 0x01900060, 0x13008A06, 0x01900060,
+       0x13008A06, 0x01900060, 0x43020A04, 0x00100060,
+       0x1B00CA05, 0x00100060, 0x23010A07, 0x01500060,
+       0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+       0x13008A06, 0x01900060, 0x13008A06, 0x01900060,
+       0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+       0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+       0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+       0x1B00CA0D, 0x00100070, 0x23010A0F, 0x01500070,
+       0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+       0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+       0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x50029404, 0x00100000, 0x32019405, 0x00100040,
+       0x0B004A06, 0x01900060, 0x0B004A06, 0x01900060,
+       0x5B02CA04, 0x00100060, 0x3B01D405, 0x00100060,
+       0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+       0x5802D404, 0x00100000, 0x3B01D405, 0x00100060,
+       0x0B004A06, 0x01900060, 0x23010A07, 0x01500060,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x5002940C, 0x00100010, 0x3201940D, 0x00100050,
+       0x0B004A0E, 0x01900070, 0x0B004A0E, 0x01900070,
+       0x5B02CA0C, 0x00100070, 0x3B01D40D, 0x00100070,
+       0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+       0x5802D40C, 0x00100010, 0x3B01D40D, 0x00100070,
+       0x0B004A0E, 0x01900070, 0x23010A0F, 0x01500070,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x40021404, 0x000F4800, 0x62031405, 0x00100040,
+       0x53028A06, 0x01900060, 0x53028A07, 0x01900060,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x000F4810, 0x6203140D, 0x00100050,
+       0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+       0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+       0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+       0x1180850D, 0x00100038, 0x1181850D, 0x00100038,
+       0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+       0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+       0x1181850D, 0x00100038, 0x2981450F, 0x01100038,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+       0x0180C506, 0x00100030, 0x0180C506, 0x00100030,
+       0x2180C50C, 0x00100030, 0x49820A0D, 0x0016A130,
+       0x41824A0D, 0x0016A130, 0x2981450F, 0x01100030,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x2000CA0C, 0x00100000, 0x49820A0D, 0x0016A130,
+       0x1980C50E, 0x00100030, 0x41824A0D, 0x0016A130,
+       0x2981450F, 0x01100030, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+       0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+       0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+       0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070,
+       0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+       0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+       0x1B014A0D, 0x00100070, 0x23010A0F, 0x01500070,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x50029404, 0x00100000, 0x32019405, 0x00100040,
+       0x03004A06, 0x01900060, 0x03004A06, 0x01900060,
+       0x6B030A0C, 0x00100060, 0x4B02140D, 0x0016A160,
+       0x4302540D, 0x0016A160, 0x23010A0F, 0x01500060,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x6B03140C, 0x00100060, 0x4B02140D, 0x0016A160,
+       0x0B004A0E, 0x01900060, 0x4302540D, 0x0016A160,
+       0x23010A0F, 0x01500060, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+       0x53028A06, 0x01900060, 0x5B02CA06, 0x01900060,
+       0x5B02CA06, 0x01900060, 0x43020A04, 0x00100060,
+       0x1B00CA05, 0x00100060, 0x53028A07, 0x0190C060,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+       0x53028A0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+       0x5B02CA0E, 0x01900070, 0x43020A0C, 0x00100070,
+       0x1B00CA0D, 0x00100070, 0x53028A0F, 0x0190C070,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+       0x5B02CA06, 0x01900060, 0x5B02CA06, 0x01900060,
+       0x53028A07, 0x0190C060, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+       0x5B02CA0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+       0x53028A0F, 0x0190C070, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_gainctl0[] = {
+       0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+       0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+       0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+       0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+       0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+       0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+       0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+       0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+       0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+       0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+       0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+       0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+       0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+       0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+       0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+       0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+       0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+       0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+       0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+       0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+       0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+       0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+       0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+       0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+       0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+       0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+       0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+       0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+       0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+       0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+       0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+       0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_gainctl1[] = {
+       0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+       0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+       0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+       0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+       0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+       0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+       0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+       0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+       0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+       0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+       0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+       0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+       0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+       0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+       0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+       0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+       0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+       0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+       0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+       0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+       0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+       0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+       0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+       0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+       0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+       0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+       0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+       0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+       0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+       0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+       0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+       0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_intlevel[] = {
+       0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
+       0x00C1188D, 0x080024D2, 0x00000070,
+};
+
+const u32 b43_ntab_iqlt0[] = {
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u32 b43_ntab_iqlt1[] = {
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+       0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u16 b43_ntab_loftlt0[] = {
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103,
+};
+
+const u16 b43_ntab_loftlt1[] = {
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+       0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+       0x0002, 0x0103,
+};
+
+const u8 b43_ntab_mcs[] = {
+       0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
+       0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
+       0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
+       0xC0, 0xC8, 0xCA, 0xD0, 0xD2, 0xD9, 0xDA, 0xDC,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x02, 0x04, 0x08, 0x09, 0x0A, 0x0C,
+       0x10, 0x11, 0x12, 0x14, 0x18, 0x19, 0x1A, 0x1C,
+       0x20, 0x21, 0x22, 0x24, 0x40, 0x41, 0x42, 0x44,
+       0x48, 0x49, 0x4A, 0x4C, 0x50, 0x51, 0x52, 0x54,
+       0x58, 0x59, 0x5A, 0x5C, 0x60, 0x61, 0x62, 0x64,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const u32 b43_ntab_noisevar10[] = {
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u32 b43_ntab_noisevar11[] = {
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+       0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u16 b43_ntab_pilot[] = {
+       0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
+       0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
+       0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
+       0xFFA0, 0xFF28, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+       0xFF82, 0xFFA0, 0xFF28, 0xFF0A, 0xFFFF, 0xFFFF,
+       0xFFFF, 0xFFFF, 0xF83F, 0xFA1F, 0xFA97, 0xFAB5,
+       0xF2BD, 0xF0BF, 0xFFFF, 0xFFFF, 0xF017, 0xF815,
+       0xF215, 0xF095, 0xF035, 0xF01D, 0xFFFF, 0xFFFF,
+       0xFF08, 0xFF02, 0xFF80, 0xFF20, 0xFF08, 0xFF02,
+       0xFF80, 0xFF20, 0xF01F, 0xF817, 0xFA15, 0xF295,
+       0xF0B5, 0xF03D, 0xFFFF, 0xFFFF, 0xF82A, 0xFA0A,
+       0xFA82, 0xFAA0, 0xF2A8, 0xF0AA, 0xFFFF, 0xFFFF,
+       0xF002, 0xF800, 0xF200, 0xF080, 0xF020, 0xF008,
+       0xFFFF, 0xFFFF, 0xF00A, 0xF802, 0xFA00, 0xF280,
+       0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
+};
+
+const u32 b43_ntab_pilotlt[] = {
+       0x76540123, 0x62407351, 0x76543201, 0x76540213,
+       0x76540123, 0x76430521,
+};
+
+const u32 b43_ntab_tdi20a0[] = {
+       0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
+       0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
+       0x00020301, 0x00030504, 0x00040708, 0x0005090B,
+       0x00064B8E, 0x00095291, 0x000A5494, 0x000B9718,
+       0x000C9927, 0x000D9B2A, 0x000EDD2E, 0x000FDF31,
+       0x000101B4, 0x000243B7, 0x000345BB, 0x000447BE,
+       0x00058982, 0x00068C05, 0x00099309, 0x000A950C,
+       0x000BD78F, 0x000CD992, 0x000DDB96, 0x000F1D99,
+       0x00005FA8, 0x0001422C, 0x0002842F, 0x00038632,
+       0x00048835, 0x0005CA38, 0x0006CCBC, 0x0009D3BF,
+       0x000B1603, 0x000C1806, 0x000D1A0A, 0x000E1C0D,
+       0x000F5E10, 0x00008093, 0x00018297, 0x0002C49A,
+       0x0003C680, 0x0004C880, 0x00060B00, 0x00070D00,
+       0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi20a1[] = {
+       0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
+       0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
+       0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
+       0x0000488E, 0x00018B91, 0x0002D214, 0x0003D418,
+       0x0004D6A7, 0x000618AA, 0x00071AAE, 0x0009DCB1,
+       0x000B1EB4, 0x000C0137, 0x000D033B, 0x000E053E,
+       0x000F4702, 0x00008905, 0x00020C09, 0x0003128C,
+       0x0004148F, 0x00051712, 0x00065916, 0x00091B19,
+       0x000A1D28, 0x000B5F2C, 0x000C41AF, 0x000D43B2,
+       0x000E85B5, 0x000F87B8, 0x0000C9BC, 0x00024CBF,
+       0x00035303, 0x00045506, 0x0005978A, 0x0006998D,
+       0x00095B90, 0x000A5D93, 0x000B9F97, 0x000C821A,
+       0x000D8400, 0x000EC600, 0x000FC800, 0x00010A00,
+       0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a0[] = {
+       0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
+       0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
+       0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
+       0x00056447, 0x00072DD0, 0x0008B6DA, 0x000A02E3,
+       0x000B8C6C, 0x000D15F6, 0x0011E484, 0x0013AE0D,
+       0x00153717, 0x00168320, 0x00180CA9, 0x00199633,
+       0x001B6548, 0x001CEED1, 0x001EB7DB, 0x0000C3E4,
+       0x00024D6D, 0x000416F7, 0x0005A585, 0x00076F0F,
+       0x0008F818, 0x000A4421, 0x000BCDAB, 0x000D9734,
+       0x00122649, 0x0013EFD2, 0x001578DC, 0x0016C4E5,
+       0x00184E6E, 0x001A17F8, 0x001BA686, 0x001D3010,
+       0x001EF999, 0x00010522, 0x00028EAC, 0x00045835,
+       0x0005E74A, 0x0007B0D3, 0x00093A5D, 0x000A85E6,
+       0x000C0F6F, 0x000DD8F9, 0x00126787, 0x00143111,
+       0x0015BA9A, 0x00170623, 0x00188FAD, 0x001A5936,
+       0x001BE84B, 0x001DB1D4, 0x001F3B5E, 0x000146E7,
+       0x00031070, 0x000499FA, 0x00062888, 0x0007F212,
+       0x00097B9B, 0x000AC7A4, 0x000C50AE, 0x000E1A37,
+       0x0012A94C, 0x001472D5, 0x0015FC5F, 0x00174868,
+       0x0018D171, 0x001A9AFB, 0x001C2989, 0x001DF313,
+       0x001F7C9C, 0x000188A5, 0x000351AF, 0x0004DB38,
+       0x0006AA4D, 0x000833D7, 0x0009BD60, 0x000B0969,
+       0x000C9273, 0x000E5BFC, 0x00132A8A, 0x0014B414,
+       0x00163D9D, 0x001789A6, 0x001912B0, 0x001ADC39,
+       0x001C6BCE, 0x001E34D8, 0x001FBE61, 0x0001CA6A,
+       0x00039374, 0x00051CFD, 0x0006EC0B, 0x00087515,
+       0x0009FE9E, 0x000B4AA7, 0x000CD3B1, 0x000E9D3A,
+       0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a1[] = {
+       0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
+       0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
+       0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
+       0x00155C37, 0x0016EACB, 0x00187454, 0x001A3DDE,
+       0x001B89E7, 0x001D12F0, 0x001F1CFA, 0x00016B88,
+       0x00033492, 0x0004BE1B, 0x00060A24, 0x0007D32E,
+       0x00095D38, 0x000AEC4C, 0x000C7555, 0x000E3EDF,
+       0x00124AE8, 0x001413F1, 0x0015A37B, 0x00172C89,
+       0x0018B593, 0x001A419C, 0x001BCB25, 0x001D942F,
+       0x001F63B9, 0x0001AD4D, 0x00037657, 0x0004C260,
+       0x00068BE9, 0x000814F3, 0x0009A47C, 0x000B2D8A,
+       0x000CB694, 0x000E429D, 0x00128C26, 0x001455B0,
+       0x0015E4BA, 0x00176E4E, 0x0018F758, 0x001A8361,
+       0x001C0CEA, 0x001DD674, 0x001FA57D, 0x0001EE8B,
+       0x0003B795, 0x0005039E, 0x0006CD27, 0x000856B1,
+       0x0009E5C6, 0x000B6F4F, 0x000CF859, 0x000E8462,
+       0x00130DEB, 0x00149775, 0x00162603, 0x0017AF8C,
+       0x00193896, 0x001AC49F, 0x001C4E28, 0x001E17B2,
+       0x0000A6C7, 0x00023050, 0x0003F9DA, 0x00054563,
+       0x00070EEC, 0x00089876, 0x000A2704, 0x000BB08D,
+       0x000D3A17, 0x001185A0, 0x00134F29, 0x0014D8B3,
+       0x001667C8, 0x0017F151, 0x00197ADB, 0x001B0664,
+       0x001C8FED, 0x001E5977, 0x0000E805, 0x0002718F,
+       0x00043B18, 0x000586A1, 0x0007502B, 0x0008D9B4,
+       0x000A68C9, 0x000BF252, 0x000DBBDC, 0x0011C7E5,
+       0x001390EE, 0x00151A78, 0x0016A906, 0x00183290,
+       0x0019BC19, 0x001B4822, 0x001CD12C, 0x001E9AB5,
+       0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdtrn[] = {
+       0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+       0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+       0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+       0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+       0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+       0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+       0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+       0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+       0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+       0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+       0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+       0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+       0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+       0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+       0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+       0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+       0xFA58FA58, 0xF895043B, 0xFF4C09C0, 0xFBC6FFA8,
+       0xFB84F384, 0x0798F6F9, 0x05760122, 0x058409F6,
+       0x0B500000, 0x05B7F542, 0x08860432, 0x06DDFEE7,
+       0xFB84F384, 0xF9D90664, 0xF7E8025C, 0x00FFF7BD,
+       0x05A805A8, 0xF7BD00FF, 0x025CF7E8, 0x0664F9D9,
+       0xF384FB84, 0xFEE706DD, 0x04320886, 0xF54205B7,
+       0x00000B50, 0x09F60584, 0x01220576, 0xF6F90798,
+       0xF384FB84, 0xFFA8FBC6, 0x09C0FF4C, 0x043BF895,
+       0x02D402D4, 0x07DE0270, 0xFC96079C, 0xF90AFE94,
+       0xFE00FF2C, 0x02D4065D, 0x092A0096, 0x0014FBB8,
+       0xFD2CFD2C, 0x076AFB3C, 0x0096F752, 0xF991FD87,
+       0xFB2C0200, 0xFEB8F960, 0x08E0FC96, 0x049802A8,
+       0xFD2CFD2C, 0x02A80498, 0xFC9608E0, 0xF960FEB8,
+       0x0200FB2C, 0xFD87F991, 0xF7520096, 0xFB3C076A,
+       0xFD2CFD2C, 0xFBB80014, 0x0096092A, 0x065D02D4,
+       0xFF2CFE00, 0xFE94F90A, 0x079CFC96, 0x027007DE,
+       0x02D402D4, 0x027007DE, 0x079CFC96, 0xFE94F90A,
+       0xFF2CFE00, 0x065D02D4, 0x0096092A, 0xFBB80014,
+       0xFD2CFD2C, 0xFB3C076A, 0xF7520096, 0xFD87F991,
+       0x0200FB2C, 0xF960FEB8, 0xFC9608E0, 0x02A80498,
+       0xFD2CFD2C, 0x049802A8, 0x08E0FC96, 0xFEB8F960,
+       0xFB2C0200, 0xF991FD87, 0x0096F752, 0x076AFB3C,
+       0xFD2CFD2C, 0x0014FBB8, 0x092A0096, 0x02D4065D,
+       0xFE00FF2C, 0xF90AFE94, 0xFC96079C, 0x07DE0270,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+       0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+       0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+       0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+       0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+       0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+       0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+       0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+       0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+       0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+       0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+       0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+       0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+       0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+       0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+       0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+       0x061C061C, 0xFF30009D, 0xFFB21141, 0xFD87FB54,
+       0xF65DFE59, 0x02EEF99E, 0x0166F03C, 0xFFF809B6,
+       0x000008A4, 0x000AF42B, 0x00EFF577, 0xFA840BF2,
+       0xFC02FF51, 0x08260F67, 0xFFF0036F, 0x0842F9C3,
+       0x00000000, 0x063DF7BE, 0xFC910010, 0xF099F7DA,
+       0x00AF03FE, 0xF40E057C, 0x0A89FF11, 0x0BD5FFF6,
+       0xF75C0000, 0xF64A0008, 0x0FC4FE9A, 0x0662FD12,
+       0x01A709A3, 0x04AC0279, 0xEEBF004E, 0xFF6300D0,
+       0xF9E4F9E4, 0x00D0FF63, 0x004EEEBF, 0x027904AC,
+       0x09A301A7, 0xFD120662, 0xFE9A0FC4, 0x0008F64A,
+       0x0000F75C, 0xFFF60BD5, 0xFF110A89, 0x057CF40E,
+       0x03FE00AF, 0xF7DAF099, 0x0010FC91, 0xF7BE063D,
+       0x00000000, 0xF9C30842, 0x036FFFF0, 0x0F670826,
+       0xFF51FC02, 0x0BF2FA84, 0xF57700EF, 0xF42B000A,
+       0x08A40000, 0x09B6FFF8, 0xF03C0166, 0xF99E02EE,
+       0xFE59F65D, 0xFB54FD87, 0x1141FFB2, 0x009DFF30,
+       0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+       0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+       0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+       0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+       0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+       0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+       0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+       0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+       0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+       0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+       0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+       0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+       0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+       0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+       0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+       0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+       0xFA58FA58, 0xF8F0FE00, 0x0448073D, 0xFDC9FE46,
+       0xF9910258, 0x089D0407, 0xFD5CF71A, 0x02AFFDE0,
+       0x083E0496, 0xFF5A0740, 0xFF7AFD97, 0x00FE01F1,
+       0x0009082E, 0xFA94FF75, 0xFECDF8EA, 0xFFB0F693,
+       0xFD2CFA58, 0x0433FF16, 0xFBA405DD, 0xFA610341,
+       0x06A606CB, 0x0039FD2D, 0x0677FA97, 0x01FA05E0,
+       0xF896003E, 0x075A068B, 0x012CFC3E, 0xFA23F98D,
+       0xFC7CFD43, 0xFF90FC0D, 0x01C10982, 0x00C601D6,
+       0xFD2CFD2C, 0x01D600C6, 0x098201C1, 0xFC0DFF90,
+       0xFD43FC7C, 0xF98DFA23, 0xFC3E012C, 0x068B075A,
+       0x003EF896, 0x05E001FA, 0xFA970677, 0xFD2D0039,
+       0x06CB06A6, 0x0341FA61, 0x05DDFBA4, 0xFF160433,
+       0xFA58FD2C, 0xF693FFB0, 0xF8EAFECD, 0xFF75FA94,
+       0x082E0009, 0x01F100FE, 0xFD97FF7A, 0x0740FF5A,
+       0x0496083E, 0xFDE002AF, 0xF71AFD5C, 0x0407089D,
+       0x0258F991, 0xFE46FDC9, 0x073D0448, 0xFE00F8F0,
+       0xFD2CFD2C, 0xFCE00500, 0xFC09FDDC, 0xFE680157,
+       0x04C70571, 0xFC3AFF21, 0xFCD70228, 0x056D0277,
+       0x0200FE00, 0x0022F927, 0xFE3C032B, 0xFC44FF3C,
+       0x03E9FBDB, 0x04570313, 0x04C9FF5C, 0x000D03B8,
+       0xFA580000, 0xFBE900D2, 0xF9D0FE0B, 0x0125FDF9,
+       0x042501BF, 0x0328FA2B, 0xFFA902F0, 0xFA250157,
+       0x0200FE00, 0x03740438, 0xFF0405FD, 0x030CFE52,
+       0x0037FB39, 0xFF6904C5, 0x04F8FD23, 0xFD31FC1B,
+       0xFD2CFD2C, 0xFC1BFD31, 0xFD2304F8, 0x04C5FF69,
+       0xFB390037, 0xFE52030C, 0x05FDFF04, 0x04380374,
+       0xFE000200, 0x0157FA25, 0x02F0FFA9, 0xFA2B0328,
+       0x01BF0425, 0xFDF90125, 0xFE0BF9D0, 0x00D2FBE9,
+       0x0000FA58, 0x03B8000D, 0xFF5C04C9, 0x03130457,
+       0xFBDB03E9, 0xFF3CFC44, 0x032BFE3C, 0xF9270022,
+       0xFE000200, 0x0277056D, 0x0228FCD7, 0xFF21FC3A,
+       0x057104C7, 0x0157FE68, 0xFDDCFC09, 0x0500FCE0,
+       0xFD2CFD2C, 0x0500FCE0, 0xFDDCFC09, 0x0157FE68,
+       0x057104C7, 0xFF21FC3A, 0x0228FCD7, 0x0277056D,
+       0xFE000200, 0xF9270022, 0x032BFE3C, 0xFF3CFC44,
+       0xFBDB03E9, 0x03130457, 0xFF5C04C9, 0x03B8000D,
+       0x0000FA58, 0x00D2FBE9, 0xFE0BF9D0, 0xFDF90125,
+       0x01BF0425, 0xFA2B0328, 0x02F0FFA9, 0x0157FA25,
+       0xFE000200, 0x04380374, 0x05FDFF04, 0xFE52030C,
+       0xFB390037, 0x04C5FF69, 0xFD2304F8, 0xFC1BFD31,
+       0xFD2CFD2C, 0xFD31FC1B, 0x04F8FD23, 0xFF6904C5,
+       0x0037FB39, 0x030CFE52, 0xFF0405FD, 0x03740438,
+       0x0200FE00, 0xFA250157, 0xFFA902F0, 0x0328FA2B,
+       0x042501BF, 0x0125FDF9, 0xF9D0FE0B, 0xFBE900D2,
+       0xFA580000, 0x000D03B8, 0x04C9FF5C, 0x04570313,
+       0x03E9FBDB, 0xFC44FF3C, 0xFE3C032B, 0x0022F927,
+       0x0200FE00, 0x056D0277, 0xFCD70228, 0xFC3AFF21,
+       0x04C70571, 0xFE680157, 0xFC09FDDC, 0xFCE00500,
+       0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+       0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+       0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+       0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+       0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+       0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+       0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+       0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+       0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+       0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+       0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+       0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+       0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+       0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+       0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+       0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+};
+
+const u32 b43_ntab_tmap[] = {
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+       0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x000AA888,
+       0x88880000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+       0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+       0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+       0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+       0xF1111110, 0x11111111, 0x11F11111, 0x00011111,
+       0x11110000, 0x1111F111, 0x11111111, 0x111111F1,
+       0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00088AAA,
+       0xAAAA0000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+       0xAAA8AAA0, 0x8AAA8AAA, 0xAA8A8A8A, 0x000AAA88,
+       0x8AAA0000, 0xAAA8A888, 0x8AA88A8A, 0x8A88A888,
+       0x08080A00, 0x0A08080A, 0x080A0A08, 0x00080808,
+       0x080A0000, 0x080A0808, 0x080A0808, 0x0A0A0A08,
+       0xA0A0A0A0, 0x80A0A080, 0x8080A0A0, 0x00008080,
+       0x80A00000, 0x80A080A0, 0xA080A0A0, 0x8080A0A0,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x99999000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+       0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+       0x22000000, 0x2222B222, 0x22222222, 0x222222B2,
+       0xB2222220, 0x22222222, 0x22D22222, 0x00000222,
+       0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+       0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+       0x33000000, 0x3333B333, 0x33333333, 0x333333B3,
+       0xB3333330, 0x33333333, 0x33D33333, 0x00000333,
+       0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+       0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+       0x99B99B00, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+       0x9B99BB99, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+       0x22222200, 0x2222F222, 0x22222222, 0x222222F2,
+       0x22222222, 0x22222222, 0x22F22222, 0x00000222,
+       0x11000000, 0x1111F111, 0x11111111, 0x11111111,
+       0xF1111111, 0x11111111, 0x11F11111, 0x01111111,
+       0xBB9BB900, 0xB9B9BB99, 0xB99BBBBB, 0xBBBB9B9B,
+       0xB9BB99BB, 0xB99999B9, 0xB9B9B99B, 0x00000BBB,
+       0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+       0xA8AA88AA, 0xA88888A8, 0xA8A8A88A, 0x0A888AAA,
+       0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+       0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00000AAA,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0xBBBBBB00, 0x999BBBBB, 0x9BB99B9B, 0xB9B9B9BB,
+       0xB9B99BBB, 0xB9B9B9BB, 0xB9BB9B99, 0x00000999,
+       0x8A000000, 0xAA88A888, 0xA88888AA, 0xA88A8A88,
+       0xA88AA88A, 0x88A8AAAA, 0xA8AA8AAA, 0x0888A88A,
+       0x0B0B0B00, 0x090B0B0B, 0x0B090B0B, 0x0909090B,
+       0x09090B0B, 0x09090B0B, 0x09090B09, 0x00000909,
+       0x0A000000, 0x0A080808, 0x080A080A, 0x080A0A08,
+       0x080A080A, 0x0808080A, 0x0A0A0A08, 0x0808080A,
+       0xB0B0B000, 0x9090B0B0, 0x90B09090, 0xB0B0B090,
+       0xB0B090B0, 0x90B0B0B0, 0xB0B09090, 0x00000090,
+       0x80000000, 0xA080A080, 0xA08080A0, 0xA0808080,
+       0xA080A080, 0x80A0A0A0, 0xA0A080A0, 0x00A0A0A0,
+       0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+       0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+       0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+       0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+       0x33000000, 0x3333F333, 0x33333333, 0x333333F3,
+       0xF3333330, 0x33333333, 0x33F33333, 0x00000333,
+       0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+       0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+       0x99000000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+       0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x88888000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+       0x88A88A00, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+       0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+       0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+       0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+       0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+       0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static inline void assert_ntab_array_sizes(void)
+{
+#undef check
+#define check(table, size)     \
+       BUILD_BUG_ON(ARRAY_SIZE(b43_ntab_##table) != B43_NTAB_##size##_SIZE)
+
+       check(adjustpower0, C0_ADJPLT);
+       check(adjustpower1, C1_ADJPLT);
+       check(bdi, BDI);
+       check(channelest, CHANEST);
+       check(estimatepowerlt0, C0_ESTPLT);
+       check(estimatepowerlt1, C1_ESTPLT);
+       check(framelookup, FRAMELT);
+       check(framestruct, FRAMESTRUCT);
+       check(gainctl0, C0_GAINCTL);
+       check(gainctl1, C1_GAINCTL);
+       check(intlevel, INTLEVEL);
+       check(iqlt0, C0_IQLT);
+       check(iqlt1, C1_IQLT);
+       check(loftlt0, C0_LOFEEDTH);
+       check(loftlt1, C1_LOFEEDTH);
+       check(mcs, MCS);
+       check(noisevar10, NOISEVAR10);
+       check(noisevar11, NOISEVAR11);
+       check(pilot, PILOT);
+       check(pilotlt, PILOTLT);
+       check(tdi20a0, TDI20A0);
+       check(tdi20a1, TDI20A1);
+       check(tdi40a0, TDI40A0);
+       check(tdi40a1, TDI40A1);
+       check(tdtrn, TDTRN);
+       check(tmap, TMAP);
+
+#undef check
+}
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
+{
+       u32 type;
+
+       type = offset & B43_NTAB_TYPEMASK;
+       offset &= 0xFFFF;
+
+       switch (type) {
+       case B43_NTAB_8BIT:
+               B43_WARN_ON(value & ~0xFF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+               break;
+       case B43_NTAB_16BIT:
+               B43_WARN_ON(value & ~0xFFFF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+               break;
+       case B43_NTAB_32BIT:
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value & 0xFFFF);
+               break;
+       default:
+               B43_WARN_ON(1);
+       }
+
+       return;
+
+       /* Some compiletime assertions... */
+       assert_ntab_array_sizes();
+}
diff --git a/package/b43/src/tables_nphy.h b/package/b43/src/tables_nphy.h
new file mode 100644 (file)
index 0000000..4d498b0
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef B43_TABLES_NPHY_H_
+#define B43_TABLES_NPHY_H_
+
+#include <linux/types.h>
+
+
+struct b43_nphy_channeltab_entry {
+       /* The channel number */
+       u8 channel;
+       /* Radio register values on channelswitch */
+       u8 radio_pll_ref;
+       u8 radio_rf_pllmod0;
+       u8 radio_rf_pllmod1;
+       u8 radio_vco_captail;
+       u8 radio_vco_cal1;
+       u8 radio_vco_cal2;
+       u8 radio_pll_lfc1;
+       u8 radio_pll_lfr1;
+       u8 radio_pll_lfc2;
+       u8 radio_lgbuf_cenbuf;
+       u8 radio_lgen_tune1;
+       u8 radio_lgen_tune2;
+       u8 radio_c1_lgbuf_atune;
+       u8 radio_c1_lgbuf_gtune;
+       u8 radio_c1_rx_rfr1;
+       u8 radio_c1_tx_pgapadtn;
+       u8 radio_c1_tx_mxbgtrim;
+       u8 radio_c2_lgbuf_atune;
+       u8 radio_c2_lgbuf_gtune;
+       u8 radio_c2_rx_rfr1;
+       u8 radio_c2_tx_pgapadtn;
+       u8 radio_c2_tx_mxbgtrim;
+       /* PHY register values on channelswitch */
+       u16 phy_bw1a;
+       u16 phy_bw2;
+       u16 phy_bw3;
+       u16 phy_bw4;
+       u16 phy_bw5;
+       u16 phy_bw6;
+       /* The channel frequency in MHz */
+       u16 freq;
+       /* An unknown value */
+       u16 unk2;
+};
+
+
+struct b43_wldev;
+
+/* Upload the default register value table.
+ * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
+ * table is uploaded. If "ignore_uploadflag" is true, we upload any value
+ * and ignore the "UPLOAD" flag. */
+void b2055_upload_inittab(struct b43_wldev *dev,
+                         bool ghz5, bool ignore_uploadflag);
+
+
+/* Get the NPHY Channel Switch Table entry for a channel number.
+ * Returns NULL on failure to find an entry. */
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
+
+
+/* The N-PHY tables. */
+
+#define B43_NTAB_TYPEMASK              0xF0000000
+#define B43_NTAB_8BIT                  0x10000000
+#define B43_NTAB_16BIT                 0x20000000
+#define B43_NTAB_32BIT                 0x30000000
+#define B43_NTAB8(table, offset)       (((table) << 10) | (offset) | B43_NTAB_8BIT)
+#define B43_NTAB16(table, offset)      (((table) << 10) | (offset) | B43_NTAB_16BIT)
+#define B43_NTAB32(table, offset)      (((table) << 10) | (offset) | B43_NTAB_32BIT)
+
+/* Static N-PHY tables */
+#define B43_NTAB_FRAMESTRUCT           B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */
+#define B43_NTAB_FRAMESTRUCT_SIZE      832
+#define B43_NTAB_FRAMELT               B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */
+#define B43_NTAB_FRAMELT_SIZE          32
+#define B43_NTAB_TMAP                  B43_NTAB32(0x0C, 0x000) /* T Map Table */
+#define B43_NTAB_TMAP_SIZE             448
+#define B43_NTAB_TDTRN                 B43_NTAB32(0x0E, 0x000) /* TDTRN Table */
+#define B43_NTAB_TDTRN_SIZE            704
+#define B43_NTAB_INTLEVEL              B43_NTAB32(0x0D, 0x000) /* Int Level Table */
+#define B43_NTAB_INTLEVEL_SIZE         7
+#define B43_NTAB_PILOT                 B43_NTAB16(0x0B, 0x000) /* Pilot Table */
+#define B43_NTAB_PILOT_SIZE            88
+#define B43_NTAB_PILOTLT               B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */
+#define B43_NTAB_PILOTLT_SIZE          6
+#define B43_NTAB_TDI20A0               B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */
+#define B43_NTAB_TDI20A0_SIZE          55
+#define B43_NTAB_TDI20A1               B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */
+#define B43_NTAB_TDI20A1_SIZE          55
+#define B43_NTAB_TDI40A0               B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */
+#define B43_NTAB_TDI40A0_SIZE          110
+#define B43_NTAB_TDI40A1               B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */
+#define B43_NTAB_TDI40A1_SIZE          110
+#define B43_NTAB_BDI                   B43_NTAB16(0x15, 0x000) /* BDI Table */
+#define B43_NTAB_BDI_SIZE              6
+#define B43_NTAB_CHANEST               B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */
+#define B43_NTAB_CHANEST_SIZE          96
+#define B43_NTAB_MCS                   B43_NTAB8 (0x12, 0x000) /* MCS Table */
+#define B43_NTAB_MCS_SIZE              128
+
+/* Volatile N-PHY tables */
+#define B43_NTAB_NOISEVAR10            B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */
+#define B43_NTAB_NOISEVAR10_SIZE       256
+#define B43_NTAB_NOISEVAR11            B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */
+#define B43_NTAB_NOISEVAR11_SIZE       256
+#define B43_NTAB_C0_ESTPLT             B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ESTPLT_SIZE                64
+#define B43_NTAB_C1_ESTPLT             B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ESTPLT_SIZE                64
+#define B43_NTAB_C0_ADJPLT             B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ADJPLT_SIZE                128
+#define B43_NTAB_C1_ADJPLT             B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ADJPLT_SIZE                128
+#define B43_NTAB_C0_GAINCTL            B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */
+#define B43_NTAB_C0_GAINCTL_SIZE       128
+#define B43_NTAB_C1_GAINCTL            B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
+#define B43_NTAB_C1_GAINCTL_SIZE       128
+#define B43_NTAB_C0_IQLT               B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */
+#define B43_NTAB_C0_IQLT_SIZE          128
+#define B43_NTAB_C1_IQLT               B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
+#define B43_NTAB_C1_IQLT_SIZE          128
+#define B43_NTAB_C0_LOFEEDTH           B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */
+#define B43_NTAB_C0_LOFEEDTH_SIZE      128
+#define B43_NTAB_C1_LOFEEDTH           B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
+#define B43_NTAB_C1_LOFEEDTH_SIZE      128
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+
+extern const u8 b43_ntab_adjustpower0[];
+extern const u8 b43_ntab_adjustpower1[];
+extern const u16 b43_ntab_bdi[];
+extern const u32 b43_ntab_channelest[];
+extern const u8 b43_ntab_estimatepowerlt0[];
+extern const u8 b43_ntab_estimatepowerlt1[];
+extern const u8 b43_ntab_framelookup[];
+extern const u32 b43_ntab_framestruct[];
+extern const u32 b43_ntab_gainctl0[];
+extern const u32 b43_ntab_gainctl1[];
+extern const u32 b43_ntab_intlevel[];
+extern const u32 b43_ntab_iqlt0[];
+extern const u32 b43_ntab_iqlt1[];
+extern const u16 b43_ntab_loftlt0[];
+extern const u16 b43_ntab_loftlt1[];
+extern const u8 b43_ntab_mcs[];
+extern const u32 b43_ntab_noisevar10[];
+extern const u32 b43_ntab_noisevar11[];
+extern const u16 b43_ntab_pilot[];
+extern const u32 b43_ntab_pilotlt[];
+extern const u32 b43_ntab_tdi20a0[];
+extern const u32 b43_ntab_tdi20a1[];
+extern const u32 b43_ntab_tdi40a0[];
+extern const u32 b43_ntab_tdi40a1[];
+extern const u32 b43_ntab_tdtrn[];
+extern const u32 b43_ntab_tmap[];
+
+
+#endif /* B43_TABLES_NPHY_H_ */
diff --git a/package/b43/src/wa.c b/package/b43/src/wa.c
new file mode 100644 (file)
index 0000000..e632125
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  PHY workarounds.
+
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "main.h"
+#include "tables.h"
+#include "phy.h"
+#include "wa.h"
+
+static void b43_wa_papd(struct b43_wldev *dev)
+{
+       u16 backup;
+
+       backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
+       b43_dummy_transmission(dev);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
+}
+
+static void b43_wa_auxclipthr(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800);
+}
+
+static void b43_wa_afcdac(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, 0x0035, 0x03FF);
+       b43_phy_write(dev, 0x0036, 0x0400);
+}
+
+static void b43_wa_txdc_offset(struct b43_wldev *dev)
+{
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051);
+}
+
+void b43_wa_initgains(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9);
+       b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+               b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F);
+       if (phy->rev <= 2)
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF);
+       b43_radio_write16(dev, 0x0002, 0x1FBF);
+
+       b43_phy_write(dev, 0x0024, 0x4680);
+       b43_phy_write(dev, 0x0020, 0x0003);
+       b43_phy_write(dev, 0x001D, 0x0F40);
+       b43_phy_write(dev, 0x001F, 0x1C00);
+       if (phy->rev <= 3)
+               b43_phy_write(dev, 0x002A,
+                       (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400);
+       else if (phy->rev == 5) {
+               b43_phy_write(dev, 0x002A,
+                       (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00);
+               b43_phy_write(dev, 0x00CC, 0x2121);
+       }
+       if (phy->rev >= 3)
+               b43_phy_write(dev, 0x00BA, 0x3ED5);
+}
+
+static void b43_wa_divider(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100);
+       b43_phy_write(dev, 0x008E, 0x58C1);
+}
+
+static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */
+{
+       if (dev->phy.rev <= 2) {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7);
+       } else {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+       }
+}
+
+static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */
+{
+       int i;
+
+       if (0 /* FIXME: For APHY.rev=2 this might be needed */) {
+               for (i = 0; i < 8; i++)
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8);
+               for (i = 8; i < 16; i++)
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8);
+       } else {
+               for (i = 0; i < 64; i++)
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i);
+       }
+}
+
+static void b43_wa_analog(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       u16 ofdmrev;
+
+       ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION;
+       if (ofdmrev > 2) {
+               if (phy->type == B43_PHYTYPE_A)
+                       b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808);
+               else
+                       b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000);
+       } else {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040);
+       }
+}
+
+static void b43_wa_dac(struct b43_wldev *dev)
+{
+       if (dev->phy.analog == 1)
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+                       (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008);
+       else
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+                       (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010);
+}
+
+static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */
+{
+       int i;
+
+       if (dev->phy.type == B43_PHYTYPE_A)
+               for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]);
+       else
+               for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]);
+}
+
+static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */
+{
+       struct b43_phy *phy = &dev->phy;
+       int i;
+
+       if (phy->type == B43_PHYTYPE_A) {
+               if (phy->rev == 2)
+                       for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]);
+               else
+                       for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]);
+       } else {
+               if (phy->rev == 1)
+                       for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]);
+               else
+                       for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]);
+       }
+}
+
+static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */
+{
+       int i;
+
+       for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+               b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
+}
+
+static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
+{
+       struct b43_phy *phy = &dev->phy;
+       int i;
+
+       if (phy->type == B43_PHYTYPE_A) {
+               if (phy->rev <= 1)
+                       for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                                       i, 0);
+               else if (phy->rev == 2)
+                       for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                                       i, b43_tab_noisescalea2[i]);
+               else if (phy->rev == 3)
+                       for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                                       i, b43_tab_noisescalea3[i]);
+               else
+                       for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                                       i, b43_tab_noisescaleg3[i]);
+       } else {
+               if (phy->rev >= 6) {
+                       if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+                               for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                                       b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                               i, b43_tab_noisescaleg3[i]);
+                       else
+                               for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                                       b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                               i, b43_tab_noisescaleg2[i]);
+               } else {
+                       for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+                                                       i, b43_tab_noisescaleg1[i]);
+               }
+       }
+}
+
+static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */
+{
+       int i;
+
+       for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+                       b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD,
+                               i, b43_tab_retard[i]);
+}
+
+static void b43_wa_txlna_gain(struct b43_wldev *dev)
+{
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000);
+}
+
+static void b43_wa_crs_reset(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, 0x002C, 0x0064);
+}
+
+static void b43_wa_2060txlna_gain(struct b43_wldev *dev)
+{
+       b43_hf_write(dev, b43_hf_read(dev) |
+                        B43_HF_2060W);
+}
+
+static void b43_wa_lms(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, 0x0055,
+               (b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004);
+}
+
+static void b43_wa_mixedsignal(struct b43_wldev *dev)
+{
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3);
+}
+
+static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */
+{
+       struct b43_phy *phy = &dev->phy;
+       int i;
+       const u16 *tab;
+
+       if (phy->type == B43_PHYTYPE_A) {
+               tab = b43_tab_sigmasqr1;
+       } else if (phy->type == B43_PHYTYPE_G) {
+               tab = b43_tab_sigmasqr2;
+       } else {
+               B43_WARN_ON(1);
+               return;
+       }
+
+       for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ,
+                                       i, tab[i]);
+       }
+}
+
+static void b43_wa_iqadc(struct b43_wldev *dev)
+{
+       if (dev->phy.analog == 4)
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0,
+                       b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000);
+}
+
+static void b43_wa_crs_ed(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       if (phy->rev == 1) {
+               b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19);
+       } else if (phy->rev == 2) {
+               b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861);
+               b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271);
+               b43_phy_write(dev, B43_PHY_ANTDWELL,
+                                 b43_phy_read(dev, B43_PHY_ANTDWELL)
+                                 | 0x0800);
+       } else {
+               b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098);
+               b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070);
+               b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080);
+               b43_phy_write(dev, B43_PHY_ANTDWELL,
+                                 b43_phy_read(dev, B43_PHY_ANTDWELL)
+                                 | 0x0800);
+       }
+}
+
+static void b43_wa_crs_thr(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, B43_PHY_CRS0,
+                       (b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000);
+}
+
+static void b43_wa_crs_blank(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A);
+}
+
+static void b43_wa_cck_shiftbits(struct b43_wldev *dev)
+{
+       b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026);
+}
+
+static void b43_wa_wrssi_offset(struct b43_wldev *dev)
+{
+       int i;
+
+       if (dev->phy.rev == 1) {
+               for (i = 0; i < 16; i++) {
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1,
+                                               i, 0x0020);
+               }
+       } else {
+               for (i = 0; i < 32; i++) {
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI,
+                                               i, 0x0820);
+               }
+       }
+}
+
+static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev)
+{
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20);
+}
+
+static void b43_wa_altagc(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       if (phy->rev == 1) {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D);
+               b43_phy_write(dev, B43_PHY_LMS, 4);
+       } else {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
+       }
+
+       b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA,
+               (b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700);
+       b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F);
+       b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80);
+       b43_phy_write(dev, B43_PHY_ANTWRSETT,
+               (b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300);
+       b43_radio_write16(dev, 0x7A,
+               b43_radio_read16(dev, 0x7A) | 0x0008);
+       b43_phy_write(dev, B43_PHY_N1P1GAIN,
+               (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008);
+       b43_phy_write(dev, B43_PHY_P1P2GAIN,
+               (b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600);
+       b43_phy_write(dev, B43_PHY_N1N2GAIN,
+               (b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700);
+       b43_phy_write(dev, B43_PHY_N1P1GAIN,
+               (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100);
+       if (phy->rev == 1) {
+               b43_phy_write(dev, B43_PHY_N1N2GAIN,
+                                 (b43_phy_read(dev, B43_PHY_N1N2GAIN)
+                                  & ~0x000F) | 0x0007);
+       }
+       b43_phy_write(dev, B43_PHY_OFDM(0x88),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C);
+       b43_phy_write(dev, B43_PHY_OFDM(0x88),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200);
+       b43_phy_write(dev, B43_PHY_OFDM(0x96),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C);
+       b43_phy_write(dev, B43_PHY_OFDM(0x89),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020);
+       b43_phy_write(dev, B43_PHY_OFDM(0x89),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200);
+       b43_phy_write(dev, B43_PHY_OFDM(0x82),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E);
+       b43_phy_write(dev, B43_PHY_OFDM(0x96),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00);
+       b43_phy_write(dev, B43_PHY_OFDM(0x81),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028);
+       b43_phy_write(dev, B43_PHY_OFDM(0x81),
+               (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00);
+       if (phy->rev == 1) {
+               b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
+               b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+                       (b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002);
+       } else {
+               b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+                       b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E);
+               b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A);
+               b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+                       (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004);
+               if (phy->rev >= 6) {
+                       b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
+                       b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+                               (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000);
+               }
+       }
+       b43_phy_write(dev, B43_PHY_DIVSRCHIDX,
+               (b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874);
+       b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00);
+       if (phy->rev == 1) {
+               b43_phy_write(dev, B43_PHY_DIVP1P2GAIN,
+                       (b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600);
+               b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E);
+               b43_phy_write(dev, B43_PHY_ANTWRSETT,
+                       (b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E);
+               b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28);
+       } else {
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28);
+       }
+       if (phy->rev >= 6) {
+               b43_phy_write(dev, B43_PHY_OFDM(0x26),
+                       b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003);
+               b43_phy_write(dev, B43_PHY_OFDM(0x26),
+                       b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000);
+       }
+       b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */
+}
+
+static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */
+{
+       b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480);
+}
+
+static void b43_wa_cpll_nonpilot(struct b43_wldev *dev)
+{
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0);
+       b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0);
+}
+
+static void b43_wa_rssi_adc(struct b43_wldev *dev)
+{
+       if (dev->phy.analog == 4)
+               b43_phy_write(dev, 0x00DC, 0x7454);
+}
+
+static void b43_wa_boards_a(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->dev->bus;
+
+       if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+           bus->boardinfo.type == SSB_BOARD_BU4306 &&
+           bus->boardinfo.rev < 0x30) {
+               b43_phy_write(dev, 0x0010, 0xE000);
+               b43_phy_write(dev, 0x0013, 0x0140);
+               b43_phy_write(dev, 0x0014, 0x0280);
+       } else {
+               if (bus->boardinfo.type == SSB_BOARD_MP4318 &&
+                   bus->boardinfo.rev < 0x20) {
+                       b43_phy_write(dev, 0x0013, 0x0210);
+                       b43_phy_write(dev, 0x0014, 0x0840);
+               } else {
+                       b43_phy_write(dev, 0x0013, 0x0140);
+                       b43_phy_write(dev, 0x0014, 0x0280);
+               }
+               if (dev->phy.rev <= 4)
+                       b43_phy_write(dev, 0x0010, 0xE000);
+               else
+                       b43_phy_write(dev, 0x0010, 0x2000);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039);
+               b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040);
+       }
+}
+
+static void b43_wa_boards_g(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->dev->bus;
+       struct b43_phy *phy = &dev->phy;
+
+       if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
+           bus->boardinfo.type != SSB_BOARD_BU4306 ||
+           bus->boardinfo.rev != 0x17) {
+               if (phy->rev < 2) {
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002);
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001);
+               } else {
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002);
+                       b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
+                       if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+                           (phy->rev >= 7)) {
+                               b43_phy_write(dev, B43_PHY_EXTG(0x11),
+                                       b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000);
+                               b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002);
+                       }
+               }
+       }
+       if (bus->sprom.boardflags_lo & B43_BFL_FEM) {
+               b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120);
+               b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480);
+       }
+}
+
+void b43_wa_all(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       if (phy->type == B43_PHYTYPE_A) {
+               switch (phy->rev) {
+               case 2:
+                       b43_wa_papd(dev);
+                       b43_wa_auxclipthr(dev);
+                       b43_wa_afcdac(dev);
+                       b43_wa_txdc_offset(dev);
+                       b43_wa_initgains(dev);
+                       b43_wa_divider(dev);
+                       b43_wa_gt(dev);
+                       b43_wa_rssi_lt(dev);
+                       b43_wa_analog(dev);
+                       b43_wa_dac(dev);
+                       b43_wa_fft(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_rt(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_art(dev);
+                       b43_wa_txlna_gain(dev);
+                       b43_wa_crs_reset(dev);
+                       b43_wa_2060txlna_gain(dev);
+                       b43_wa_lms(dev);
+                       break;
+               case 3:
+                       b43_wa_papd(dev);
+                       b43_wa_mixedsignal(dev);
+                       b43_wa_rssi_lt(dev);
+                       b43_wa_txdc_offset(dev);
+                       b43_wa_initgains(dev);
+                       b43_wa_dac(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_msst(dev);
+                       b43_wa_analog(dev);
+                       b43_wa_gt(dev);
+                       b43_wa_txpuoff_rxpuon(dev);
+                       b43_wa_txlna_gain(dev);
+                       break;
+               case 5:
+                       b43_wa_iqadc(dev);
+               case 6:
+                       b43_wa_papd(dev);
+                       b43_wa_rssi_lt(dev);
+                       b43_wa_txdc_offset(dev);
+                       b43_wa_initgains(dev);
+                       b43_wa_dac(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_msst(dev);
+                       b43_wa_analog(dev);
+                       b43_wa_gt(dev);
+                       b43_wa_txpuoff_rxpuon(dev);
+                       b43_wa_txlna_gain(dev);
+                       break;
+               case 7:
+                       b43_wa_iqadc(dev);
+                       b43_wa_papd(dev);
+                       b43_wa_rssi_lt(dev);
+                       b43_wa_txdc_offset(dev);
+                       b43_wa_initgains(dev);
+                       b43_wa_dac(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_msst(dev);
+                       b43_wa_analog(dev);
+                       b43_wa_gt(dev);
+                       b43_wa_txpuoff_rxpuon(dev);
+                       b43_wa_txlna_gain(dev);
+                       b43_wa_rssi_adc(dev);
+               default:
+                       B43_WARN_ON(1);
+               }
+               b43_wa_boards_a(dev);
+       } else if (phy->type == B43_PHYTYPE_G) {
+               switch (phy->rev) {
+               case 1://XXX review rev1
+                       b43_wa_crs_ed(dev);
+                       b43_wa_crs_thr(dev);
+                       b43_wa_crs_blank(dev);
+                       b43_wa_cck_shiftbits(dev);
+                       b43_wa_fft(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_rt(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_art(dev);
+                       b43_wa_wrssi_offset(dev);
+                       b43_wa_altagc(dev);
+                       break;
+               case 2:
+               case 6:
+               case 7:
+               case 8:
+               case 9:
+                       b43_wa_tr_ltov(dev);
+                       b43_wa_crs_ed(dev);
+                       b43_wa_rssi_lt(dev);
+                       b43_wa_nft(dev);
+                       b43_wa_nst(dev);
+                       b43_wa_msst(dev);
+                       b43_wa_wrssi_offset(dev);
+                       b43_wa_altagc(dev);
+                       b43_wa_analog(dev);
+                       b43_wa_txpuoff_rxpuon(dev);
+                       break;
+               default:
+                       B43_WARN_ON(1);
+               }
+               b43_wa_boards_g(dev);
+       } else { /* No N PHY support so far */
+               B43_WARN_ON(1);
+       }
+
+       b43_wa_cpll_nonpilot(dev);
+}
diff --git a/package/b43/src/wa.h b/package/b43/src/wa.h
new file mode 100644 (file)
index 0000000..e163c5e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef B43_WA_H_
+#define B43_WA_H_
+
+void b43_wa_initgains(struct b43_wldev *dev);
+void b43_wa_all(struct b43_wldev *dev);
+
+#endif /* B43_WA_H_ */
index 0bd6f8a348a8a195821ff8ec5721c167b0443bca..4014b6c8272b4189f22168e73690e9744d4eca6a 100644 (file)
@@ -5,7 +5,7 @@
   Transmission (TX/RX) related functions.
 
   Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 #include "xmit.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 
-/* Extract the bitrate out of a CCK PLCP header. */
-static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+
+/* Extract the bitrate index out of a CCK PLCP header. */
+static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
 {
        switch (plcp->raw[0]) {
        case 0x0A:
-               return B43_CCK_RATE_1MB;
+               return 0;
        case 0x14:
-               return B43_CCK_RATE_2MB;
+               return 1;
        case 0x37:
-               return B43_CCK_RATE_5MB;
+               return 2;
        case 0x6E:
-               return B43_CCK_RATE_11MB;
+               return 3;
        }
        B43_WARN_ON(1);
-       return 0;
+       return -1;
 }
 
-/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+/* Extract the bitrate index out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
 {
+       int base = aphy ? 0 : 4;
+
        switch (plcp->raw[0] & 0xF) {
        case 0xB:
-               return B43_OFDM_RATE_6MB;
+               return base + 0;
        case 0xF:
-               return B43_OFDM_RATE_9MB;
+               return base + 1;
        case 0xA:
-               return B43_OFDM_RATE_12MB;
+               return base + 2;
        case 0xE:
-               return B43_OFDM_RATE_18MB;
+               return base + 3;
        case 0x9:
-               return B43_OFDM_RATE_24MB;
+               return base + 4;
        case 0xD:
-               return B43_OFDM_RATE_36MB;
+               return base + 5;
        case 0x8:
-               return B43_OFDM_RATE_48MB;
+               return base + 6;
        case 0xC:
-               return B43_OFDM_RATE_54MB;
+               return base + 7;
        }
        B43_WARN_ON(1);
-       return 0;
+       return -1;
 }
 
 u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
@@ -177,18 +179,21 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
        return 0;
 }
 
-static void generate_txhdr_fw4(struct b43_wldev *dev,
-                              struct b43_txhdr_fw4 *txhdr,
-                              const unsigned char *fragment_data,
-                              unsigned int fragment_len,
-                              const struct ieee80211_tx_control *txctl,
-                              u16 cookie)
+/* Generate a TX data header. */
+int b43_generate_txhdr(struct b43_wldev *dev,
+                      u8 *_txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+                      const struct ieee80211_tx_control *txctl,
+                      u16 cookie)
 {
+       struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
        const struct b43_phy *phy = &dev->phy;
        const struct ieee80211_hdr *wlhdr =
            (const struct ieee80211_hdr *)fragment_data;
        int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
        u16 fctl = le16_to_cpu(wlhdr->frame_control);
+       struct ieee80211_rate *fbrate;
        u8 rate, rate_fb;
        int rate_ofdm, rate_fb_ofdm;
        unsigned int plcp_fragment_len;
@@ -198,9 +203,11 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
        memset(txhdr, 0, sizeof(*txhdr));
 
-       rate = txctl->tx_rate;
+       WARN_ON(!txctl->tx_rate);
+       rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
        rate_ofdm = b43_is_ofdm_rate(rate);
-       rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+       fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
+       rate_fb = fbrate->hw_value;
        rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
 
        if (rate_ofdm)
@@ -219,11 +226,10 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
                 * use the original dur_id field. */
                txhdr->dur_fb = wlhdr->duration_id;
        } else {
-               int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
                txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-                                                                dev->wl->if_id,
+                                                                txctl->vif,
                                                                 fragment_len,
-                                                                fbrate_base100kbps);
+                                                                fbrate);
        }
 
        plcp_fragment_len = fragment_len + FCS_LEN;
@@ -235,29 +241,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
                B43_WARN_ON(key_idx >= dev->max_nr_keys);
                key = &(dev->key[key_idx]);
-               B43_WARN_ON(!key->keyconf);
+
+               if (unlikely(!key->keyconf)) {
+                       /* This key is invalid. This might only happen
+                        * in a short timeframe after machine resume before
+                        * we were able to reconfigure keys.
+                        * Drop this packet completely. Do not transmit it
+                        * unencrypted to avoid leaking information. */
+                       return -ENOKEY;
+               }
 
                /* Hardware appends ICV. */
                plcp_fragment_len += txctl->icv_len;
 
                key_idx = b43_kidx_to_fw(dev, key_idx);
-               mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
-                          B43_TX4_MAC_KEYIDX;
-               mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
-                          B43_TX4_MAC_KEYALG;
+               mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
+                          B43_TXH_MAC_KEYIDX;
+               mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
+                          B43_TXH_MAC_KEYALG;
                wlhdr_len = ieee80211_get_hdrlen(fctl);
                iv_len = min((size_t) txctl->iv_len,
                             ARRAY_SIZE(txhdr->iv));
                memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
        }
-       b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
-                             plcp_fragment_len, rate);
+       if (b43_is_old_txhdr_format(dev)) {
+               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+                                     plcp_fragment_len, rate);
+       } else {
+               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+                                     plcp_fragment_len, rate);
+       }
        b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
                              plcp_fragment_len, rate_fb);
 
        /* Extra Frame Types */
        if (rate_fb_ofdm)
-               extra_ft |= B43_TX4_EFT_FBOFDM;
+               extra_ft |= B43_TXH_EFT_FB_OFDM;
+       else
+               extra_ft |= B43_TXH_EFT_FB_CCK;
 
        /* Set channel radio code. Note that the micrcode ORs 0x100 to
         * this value before comparing it to the value in SHM, if this
@@ -267,18 +288,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
        /* PHY TX Control word */
        if (rate_ofdm)
-               phy_ctl |= B43_TX4_PHY_OFDM;
-       if (dev->short_preamble)
-               phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
-       switch (txctl->antenna_sel_tx) {
-       case 0:
-               phy_ctl |= B43_TX4_PHY_ANTLAST;
+               phy_ctl |= B43_TXH_PHY_ENC_OFDM;
+       else
+               phy_ctl |= B43_TXH_PHY_ENC_CCK;
+       if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+               phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
+
+       switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+       case 0: /* Default */
+               phy_ctl |= B43_TXH_PHY_ANT01AUTO;
                break;
-       case 1:
-               phy_ctl |= B43_TX4_PHY_ANT0;
+       case 1: /* Antenna 0 */
+               phy_ctl |= B43_TXH_PHY_ANT0;
                break;
-       case 2:
-               phy_ctl |= B43_TX4_PHY_ANT1;
+       case 2: /* Antenna 1 */
+               phy_ctl |= B43_TXH_PHY_ANT1;
+               break;
+       case 3: /* Antenna 2 */
+               phy_ctl |= B43_TXH_PHY_ANT2;
+               break;
+       case 4: /* Antenna 3 */
+               phy_ctl |= B43_TXH_PHY_ANT3;
                break;
        default:
                B43_WARN_ON(1);
@@ -286,14 +316,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
        /* MAC control */
        if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
-               mac_ctl |= B43_TX4_MAC_ACK;
+               mac_ctl |= B43_TXH_MAC_ACK;
        if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
              ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
-               mac_ctl |= B43_TX4_MAC_HWSEQ;
+               mac_ctl |= B43_TXH_MAC_HWSEQ;
        if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
-               mac_ctl |= B43_TX4_MAC_STMSDU;
+               mac_ctl |= B43_TXH_MAC_STMSDU;
        if (phy->type == B43_PHYTYPE_A)
-               mac_ctl |= B43_TX4_MAC_5GHZ;
+               mac_ctl |= B43_TXH_MAC_5GHZ;
+       if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+               mac_ctl |= B43_TXH_MAC_LONGFRAME;
 
        /* Generate the RTS or CTS-to-self frame */
        if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
@@ -302,66 +334,94 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
                struct ieee80211_hdr *hdr;
                int rts_rate, rts_rate_fb;
                int rts_rate_ofdm, rts_rate_fb_ofdm;
+               struct b43_plcp_hdr6 *plcp;
 
-               rts_rate = txctl->rts_cts_rate;
+               WARN_ON(!txctl->rts_cts_rate);
+               rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
                rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
                rts_rate_fb = b43_calc_fallback_rate(rts_rate);
                rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
                if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-                       ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+                       struct ieee80211_cts *cts;
+
+                       if (b43_is_old_txhdr_format(dev)) {
+                               cts = (struct ieee80211_cts *)
+                                       (txhdr->old_format.rts_frame);
+                       } else {
+                               cts = (struct ieee80211_cts *)
+                                       (txhdr->new_format.rts_frame);
+                       }
+                       ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
                                                fragment_data, fragment_len,
-                                               txctl,
-                                               (struct ieee80211_cts *)(txhdr->
-                                                                        rts_frame));
-                       mac_ctl |= B43_TX4_MAC_SENDCTS;
+                                               txctl, cts);
+                       mac_ctl |= B43_TXH_MAC_SENDCTS;
                        len = sizeof(struct ieee80211_cts);
                } else {
-                       ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
-                                         fragment_data, fragment_len, txctl,
-                                         (struct ieee80211_rts *)(txhdr->
-                                                                  rts_frame));
-                       mac_ctl |= B43_TX4_MAC_SENDRTS;
+                       struct ieee80211_rts *rts;
+
+                       if (b43_is_old_txhdr_format(dev)) {
+                               rts = (struct ieee80211_rts *)
+                                       (txhdr->old_format.rts_frame);
+                       } else {
+                               rts = (struct ieee80211_rts *)
+                                       (txhdr->new_format.rts_frame);
+                       }
+                       ieee80211_rts_get(dev->wl->hw, txctl->vif,
+                                         fragment_data, fragment_len,
+                                         txctl, rts);
+                       mac_ctl |= B43_TXH_MAC_SENDRTS;
                        len = sizeof(struct ieee80211_rts);
                }
                len += FCS_LEN;
-               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-                                                              rts_plcp), len,
-                                     rts_rate);
-               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-                                                              rts_plcp_fb),
+
+               /* Generate the PLCP headers for the RTS/CTS frame */
+               if (b43_is_old_txhdr_format(dev))
+                       plcp = &txhdr->old_format.rts_plcp;
+               else
+                       plcp = &txhdr->new_format.rts_plcp;
+               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
+                                     len, rts_rate);
+               plcp = &txhdr->rts_plcp_fb;
+               b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
                                      len, rts_rate_fb);
-               hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+
+               if (b43_is_old_txhdr_format(dev)) {
+                       hdr = (struct ieee80211_hdr *)
+                               (&txhdr->old_format.rts_frame);
+               } else {
+                       hdr = (struct ieee80211_hdr *)
+                               (&txhdr->new_format.rts_frame);
+               }
                txhdr->rts_dur_fb = hdr->duration_id;
+
                if (rts_rate_ofdm) {
-                       extra_ft |= B43_TX4_EFT_RTSOFDM;
+                       extra_ft |= B43_TXH_EFT_RTS_OFDM;
                        txhdr->phy_rate_rts =
                            b43_plcp_get_ratecode_ofdm(rts_rate);
-               } else
+               } else {
+                       extra_ft |= B43_TXH_EFT_RTS_CCK;
                        txhdr->phy_rate_rts =
                            b43_plcp_get_ratecode_cck(rts_rate);
+               }
                if (rts_rate_fb_ofdm)
-                       extra_ft |= B43_TX4_EFT_RTSFBOFDM;
-               mac_ctl |= B43_TX4_MAC_LONGFRAME;
+                       extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
+               else
+                       extra_ft |= B43_TXH_EFT_RTSFB_CCK;
        }
 
        /* Magic cookie */
-       txhdr->cookie = cpu_to_le16(cookie);
+       if (b43_is_old_txhdr_format(dev))
+               txhdr->old_format.cookie = cpu_to_le16(cookie);
+       else
+               txhdr->new_format.cookie = cpu_to_le16(cookie);
 
        /* Apply the bitfields */
        txhdr->mac_ctl = cpu_to_le32(mac_ctl);
        txhdr->phy_ctl = cpu_to_le16(phy_ctl);
        txhdr->extra_ft = extra_ft;
-}
 
-void b43_generate_txhdr(struct b43_wldev *dev,
-                       u8 * txhdr,
-                       const unsigned char *fragment_data,
-                       unsigned int fragment_len,
-                       const struct ieee80211_tx_control *txctl, u16 cookie)
-{
-       generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
-                          fragment_data, fragment_len, txctl, cookie);
+       return 0;
 }
 
 static s8 b43_rssi_postprocess(struct b43_wldev *dev,
@@ -384,7 +444,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
                        else
                                tmp -= 3;
                } else {
-                       if (dev->dev->bus->sprom.r1.
+                       if (dev->dev->bus->sprom.
                            boardflags_lo & B43_BFL_RSSI) {
                                if (in_rssi > 63)
                                        in_rssi = 63;
@@ -451,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        u16 phystat0, phystat3, chanstat, mactime;
        u32 macstat;
        u16 chanid;
+       u16 phytype;
        u8 jssi;
        int padding;
 
@@ -463,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        macstat = le32_to_cpu(rxhdr->mac_status);
        mactime = le16_to_cpu(rxhdr->mac_time);
        chanstat = le16_to_cpu(rxhdr->channel);
+       phytype = chanstat & B43_RX_CHAN_PHYTYPE;
 
        if (macstat & B43_RX_MAC_FCSERR)
                dev->wl->ieee_stats.dot11FCSErrorCount++;
@@ -488,7 +550,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        }
        wlhdr = (struct ieee80211_hdr *)(skb->data);
        fctl = le16_to_cpu(wlhdr->frame_control);
-       skb_trim(skb, skb->len - FCS_LEN);
 
        if (macstat & B43_RX_MAC_DEC) {
                unsigned int keyidx;
@@ -521,31 +582,59 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        /* the next line looks wrong, but is what mac80211 wants */
        status.signal = (jssi * 100) / B43_RX_MAX_SSI;
        if (phystat0 & B43_RX_PHYST0_OFDM)
-               status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+               status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
+                                               phytype == B43_PHYTYPE_A);
        else
-               status.rate = b43_plcp_get_bitrate_cck(plcp);
+               status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
        status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
-       status.mactime = mactime;
+
+       /*
+        * If monitors are present get full 64-bit timestamp. This
+        * code assumes we get to process the packet within 16 bits
+        * of timestamp, i.e. about 65 milliseconds after the PHY
+        * received the first symbol.
+        */
+       if (dev->wl->radiotap_enabled) {
+               u16 low_mactime_now;
+
+               b43_tsf_read(dev, &status.mactime);
+               low_mactime_now = status.mactime;
+               status.mactime = status.mactime & ~0xFFFFULL;
+               status.mactime += mactime;
+               if (low_mactime_now <= mactime)
+                       status.mactime -= 0x10000;
+               status.flag |= RX_FLAG_TSFT;
+       }
 
        chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
        switch (chanstat & B43_RX_CHAN_PHYTYPE) {
        case B43_PHYTYPE_A:
-               status.phymode = MODE_IEEE80211A;
-               status.freq = chanid;
-               status.channel = b43_freq_to_channel_a(chanid);
-               break;
-       case B43_PHYTYPE_B:
-               status.phymode = MODE_IEEE80211B;
-               status.freq = chanid + 2400;
-               status.channel = b43_freq_to_channel_bg(chanid + 2400);
+               status.band = IEEE80211_BAND_5GHZ;
+               B43_WARN_ON(1);
+               /* FIXME: We don't really know which value the "chanid" contains.
+                *        So the following assignment might be wrong. */
+               status.freq = b43_channel_to_freq_5ghz(chanid);
                break;
        case B43_PHYTYPE_G:
-               status.phymode = MODE_IEEE80211G;
+               status.band = IEEE80211_BAND_2GHZ;
+               /* chanid is the radio channel cookie value as used
+                * to tune the radio. */
                status.freq = chanid + 2400;
-               status.channel = b43_freq_to_channel_bg(chanid + 2400);
+               break;
+       case B43_PHYTYPE_N:
+               /* chanid is the SHM channel cookie. Which is the plain
+                * channel number in b43. */
+               if (chanstat & B43_RX_CHAN_5GHZ) {
+                       status.band = IEEE80211_BAND_5GHZ;
+                       status.freq = b43_freq_to_channel_5ghz(chanid);
+               } else {
+                       status.band = IEEE80211_BAND_2GHZ;
+                       status.freq = b43_freq_to_channel_2ghz(chanid);
+               }
                break;
        default:
                B43_WARN_ON(1);
+               goto drop;
        }
 
        dev->stats.last_rx = jiffies;
@@ -575,10 +664,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
                        dev->wl->ieee_stats.dot11RTSSuccessCount++;
        }
 
-       if (b43_using_pio(dev))
-               b43_pio_handle_txstatus(dev, status);
-       else
-               b43_dma_handle_txstatus(dev, status);
+       b43_dma_handle_txstatus(dev, status);
 }
 
 /* Handle TX status report as received through DMA/PIO queues */
@@ -607,19 +693,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
 /* Stop any TX operation on the device (suspend the hardware queues) */
 void b43_tx_suspend(struct b43_wldev *dev)
 {
-       if (b43_using_pio(dev))
-               b43_pio_freeze_txqueues(dev);
-       else
-               b43_dma_tx_suspend(dev);
+       b43_dma_tx_suspend(dev);
 }
 
 /* Resume any TX operation on the device (resume the hardware queues) */
 void b43_tx_resume(struct b43_wldev *dev)
 {
-       if (b43_using_pio(dev))
-               b43_pio_thaw_txqueues(dev);
-       else
-               b43_dma_tx_resume(dev);
+       b43_dma_tx_resume(dev);
 }
 
 #if 0
index 03bddd251618472b9f102c0973bd7dc8531741d3..41765039552bdf6792bd7b4e3cae14ba02fec0ef 100644 (file)
@@ -19,74 +19,166 @@ _b43_declare_plcp_hdr(6);
 #undef _b43_declare_plcp_hdr
 
 /* TX header for v4 firmware */
-struct b43_txhdr_fw4 {
-       __le32 mac_ctl;         /* MAC TX control */
-       __le16 mac_frame_ctl;   /* Copy of the FrameControl field */
+struct b43_txhdr {
+       __le32 mac_ctl;                 /* MAC TX control */
+       __le16 mac_frame_ctl;           /* Copy of the FrameControl field */
        __le16 tx_fes_time_norm;        /* TX FES Time Normal */
-       __le16 phy_ctl;         /* PHY TX control */
-       __le16 phy_ctl_0;       /* Unused */
-       __le16 phy_ctl_1;       /* Unused */
-       __le16 phy_ctl_rts_0;   /* Unused */
-       __le16 phy_ctl_rts_1;   /* Unused */
-       __u8 phy_rate;          /* PHY rate */
-       __u8 phy_rate_rts;      /* PHY rate for RTS/CTS */
-       __u8 extra_ft;          /* Extra Frame Types */
-       __u8 chan_radio_code;   /* Channel Radio Code */
-       __u8 iv[16];            /* Encryption IV */
-       __u8 tx_receiver[6];    /* TX Frame Receiver address */
-       __le16 tx_fes_time_fb;  /* TX FES Time Fallback */
-       struct b43_plcp_hdr6 rts_plcp_fb;       /* RTS fallback PLCP */
-       __le16 rts_dur_fb;      /* RTS fallback duration */
-       struct b43_plcp_hdr6 plcp_fb;   /* Fallback PLCP */
-       __le16 dur_fb;          /* Fallback duration */
-       __le16 mm_dur_time;     /* Unused */
-       __le16 mm_dur_time_fb;  /* Unused */
-       __le32 time_stamp;      /* Timestamp */
-        PAD_BYTES(2);
-       __le16 cookie;          /* TX frame cookie */
-       __le16 tx_status;       /* TX status */
-       struct b43_plcp_hdr6 rts_plcp;  /* RTS PLCP */
-       __u8 rts_frame[16];     /* The RTS frame (if used) */
-        PAD_BYTES(2);
-       struct b43_plcp_hdr6 plcp;      /* Main PLCP */
+       __le16 phy_ctl;                 /* PHY TX control */
+       __le16 phy_ctl1;                /* PHY TX control word 1 */
+       __le16 phy_ctl1_fb;             /* PHY TX control word 1 for fallback rates */
+       __le16 phy_ctl1_rts;            /* PHY TX control word 1 RTS */
+       __le16 phy_ctl1_rts_fb;         /* PHY TX control word 1 RTS for fallback rates */
+       __u8 phy_rate;                  /* PHY rate */
+       __u8 phy_rate_rts;              /* PHY rate for RTS/CTS */
+       __u8 extra_ft;                  /* Extra Frame Types */
+       __u8 chan_radio_code;           /* Channel Radio Code */
+       __u8 iv[16];                    /* Encryption IV */
+       __u8 tx_receiver[6];            /* TX Frame Receiver address */
+       __le16 tx_fes_time_fb;          /* TX FES Time Fallback */
+       struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */
+       __le16 rts_dur_fb;              /* RTS fallback duration */
+       struct b43_plcp_hdr6 plcp_fb;   /* Fallback PLCP header */
+       __le16 dur_fb;                  /* Fallback duration */
+       __le16 mimo_modelen;            /* MIMO mode length */
+       __le16 mimo_ratelen_fb;         /* MIMO fallback rate length */
+       __le32 timeout;                 /* Timeout */
+
+       union {
+               /* The new r410 format. */
+               struct {
+                       __le16 mimo_antenna;            /* MIMO antenna select */
+                       __le16 preload_size;            /* Preload size */
+                       PAD_BYTES(2);
+                       __le16 cookie;                  /* TX frame cookie */
+                       __le16 tx_status;               /* TX status */
+                       struct b43_plcp_hdr6 rts_plcp;  /* RTS PLCP header */
+                       __u8 rts_frame[16];             /* The RTS frame (if used) */
+                       PAD_BYTES(2);
+                       struct b43_plcp_hdr6 plcp;      /* Main PLCP header */
+               } new_format __attribute__ ((__packed__));
+
+               /* The old r351 format. */
+               struct {
+                       PAD_BYTES(2);
+                       __le16 cookie;                  /* TX frame cookie */
+                       __le16 tx_status;               /* TX status */
+                       struct b43_plcp_hdr6 rts_plcp;  /* RTS PLCP header */
+                       __u8 rts_frame[16];             /* The RTS frame (if used) */
+                       PAD_BYTES(2);
+                       struct b43_plcp_hdr6 plcp;      /* Main PLCP header */
+               } old_format __attribute__ ((__packed__));
+
+       } __attribute__ ((__packed__));
 } __attribute__ ((__packed__));
 
 /* MAC TX control */
-#define B43_TX4_MAC_KEYIDX             0x0FF00000      /* Security key index */
-#define B43_TX4_MAC_KEYIDX_SHIFT       20
-#define B43_TX4_MAC_KEYALG             0x00070000      /* Security key algorithm */
-#define B43_TX4_MAC_KEYALG_SHIFT       16
-#define B43_TX4_MAC_LIFETIME   0x00001000
-#define B43_TX4_MAC_FRAMEBURST 0x00000800
-#define B43_TX4_MAC_SENDCTS            0x00000400
-#define B43_TX4_MAC_AMPDU              0x00000300
-#define B43_TX4_MAC_AMPDU_SHIFT        8
-#define B43_TX4_MAC_5GHZ               0x00000080
-#define B43_TX4_MAC_IGNPMQ             0x00000020
-#define B43_TX4_MAC_HWSEQ              0x00000010      /* Use Hardware Sequence Number */
-#define B43_TX4_MAC_STMSDU             0x00000008      /* Start MSDU */
-#define B43_TX4_MAC_SENDRTS            0x00000004
-#define B43_TX4_MAC_LONGFRAME  0x00000002
-#define B43_TX4_MAC_ACK                0x00000001
+#define B43_TXH_MAC_USEFBR             0x10000000 /* Use fallback rate for this AMPDU */
+#define B43_TXH_MAC_KEYIDX             0x0FF00000 /* Security key index */
+#define B43_TXH_MAC_KEYIDX_SHIFT       20
+#define B43_TXH_MAC_KEYALG             0x00070000 /* Security key algorithm */
+#define B43_TXH_MAC_KEYALG_SHIFT       16
+#define B43_TXH_MAC_AMIC               0x00008000 /* AMIC */
+#define B43_TXH_MAC_RIFS               0x00004000 /* Use RIFS */
+#define B43_TXH_MAC_LIFETIME           0x00002000 /* Lifetime */
+#define B43_TXH_MAC_FRAMEBURST         0x00001000 /* Frameburst */
+#define B43_TXH_MAC_SENDCTS            0x00000800 /* Send CTS-to-self */
+#define B43_TXH_MAC_AMPDU              0x00000600 /* AMPDU status */
+#define  B43_TXH_MAC_AMPDU_MPDU                0x00000000 /* Regular MPDU, not an AMPDU */
+#define  B43_TXH_MAC_AMPDU_FIRST       0x00000200 /* First MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_INTER       0x00000400 /* Intermediate MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_LAST                0x00000600 /* Last (or only) MPDU of AMPDU */
+#define B43_TXH_MAC_40MHZ              0x00000100 /* Use 40 MHz bandwidth */
+#define B43_TXH_MAC_5GHZ               0x00000080 /* 5GHz band */
+#define B43_TXH_MAC_DFCS               0x00000040 /* DFCS */
+#define B43_TXH_MAC_IGNPMQ             0x00000020 /* Ignore PMQ */
+#define B43_TXH_MAC_HWSEQ              0x00000010 /* Use Hardware Sequence Number */
+#define B43_TXH_MAC_STMSDU             0x00000008 /* Start MSDU */
+#define B43_TXH_MAC_SENDRTS            0x00000004 /* Send RTS */
+#define B43_TXH_MAC_LONGFRAME          0x00000002 /* Long frame */
+#define B43_TXH_MAC_ACK                        0x00000001 /* Immediate ACK */
 
 /* Extra Frame Types */
-#define B43_TX4_EFT_FBOFDM             0x0001  /* Data frame fallback rate type */
-#define B43_TX4_EFT_RTSOFDM            0x0004  /* RTS/CTS rate type */
-#define B43_TX4_EFT_RTSFBOFDM  0x0010  /* RTS/CTS fallback rate type */
+#define B43_TXH_EFT_FB                 0x03 /* Data frame fallback encoding */
+#define  B43_TXH_EFT_FB_CCK            0x00 /* CCK */
+#define  B43_TXH_EFT_FB_OFDM           0x01 /* OFDM */
+#define  B43_TXH_EFT_FB_EWC            0x02 /* EWC */
+#define  B43_TXH_EFT_FB_N              0x03 /* N */
+#define B43_TXH_EFT_RTS                        0x0C /* RTS/CTS encoding */
+#define  B43_TXH_EFT_RTS_CCK           0x00 /* CCK */
+#define  B43_TXH_EFT_RTS_OFDM          0x04 /* OFDM */
+#define  B43_TXH_EFT_RTS_EWC           0x08 /* EWC */
+#define  B43_TXH_EFT_RTS_N             0x0C /* N */
+#define B43_TXH_EFT_RTSFB              0x30 /* RTS/CTS fallback encoding */
+#define  B43_TXH_EFT_RTSFB_CCK         0x00 /* CCK */
+#define  B43_TXH_EFT_RTSFB_OFDM                0x10 /* OFDM */
+#define  B43_TXH_EFT_RTSFB_EWC         0x20 /* EWC */
+#define  B43_TXH_EFT_RTSFB_N           0x30 /* N */
 
 /* PHY TX control word */
-#define B43_TX4_PHY_OFDM               0x0001  /* Data frame rate type */
-#define B43_TX4_PHY_SHORTPRMBL 0x0010  /* Use short preamble */
-#define B43_TX4_PHY_ANT                0x03C0  /* Antenna selection */
-#define  B43_TX4_PHY_ANT0              0x0000  /* Use antenna 0 */
-#define  B43_TX4_PHY_ANT1              0x0100  /* Use antenna 1 */
-#define  B43_TX4_PHY_ANTLAST   0x0300  /* Use last used antenna */
-
-void b43_generate_txhdr(struct b43_wldev *dev,
-                       u8 * txhdr,
-                       const unsigned char *fragment_data,
-                       unsigned int fragment_len,
-                       const struct ieee80211_tx_control *txctl, u16 cookie);
+#define B43_TXH_PHY_ENC                        0x0003 /* Data frame encoding */
+#define  B43_TXH_PHY_ENC_CCK           0x0000 /* CCK */
+#define  B43_TXH_PHY_ENC_OFDM          0x0001 /* OFDM */
+#define  B43_TXH_PHY_ENC_EWC           0x0002 /* EWC */
+#define  B43_TXH_PHY_ENC_N             0x0003 /* N */
+#define B43_TXH_PHY_SHORTPRMBL         0x0010 /* Use short preamble */
+#define B43_TXH_PHY_ANT                        0x03C0 /* Antenna selection */
+#define  B43_TXH_PHY_ANT0              0x0000 /* Use antenna 0 */
+#define  B43_TXH_PHY_ANT1              0x0040 /* Use antenna 1 */
+#define  B43_TXH_PHY_ANT01AUTO         0x00C0 /* Use antenna 0/1 auto */
+#define  B43_TXH_PHY_ANT2              0x0100 /* Use antenna 2 */
+#define  B43_TXH_PHY_ANT3              0x0200 /* Use antenna 3 */
+#define B43_TXH_PHY_TXPWR              0xFC00 /* TX power */
+#define B43_TXH_PHY_TXPWR_SHIFT                10
+
+/* PHY TX control word 1 */
+#define B43_TXH_PHY1_BW                        0x0007 /* Bandwidth */
+#define  B43_TXH_PHY1_BW_10            0x0000 /* 10 MHz */
+#define  B43_TXH_PHY1_BW_10U           0x0001 /* 10 MHz upper */
+#define  B43_TXH_PHY1_BW_20            0x0002 /* 20 MHz */
+#define  B43_TXH_PHY1_BW_20U           0x0003 /* 20 MHz upper */
+#define  B43_TXH_PHY1_BW_40            0x0004 /* 40 MHz */
+#define  B43_TXH_PHY1_BW_40DUP         0x0005 /* 50 MHz duplicate */
+#define B43_TXH_PHY1_MODE              0x0038 /* Mode */
+#define  B43_TXH_PHY1_MODE_SISO                0x0000 /* SISO */
+#define  B43_TXH_PHY1_MODE_CDD         0x0008 /* CDD */
+#define  B43_TXH_PHY1_MODE_STBC                0x0010 /* STBC */
+#define  B43_TXH_PHY1_MODE_SDM         0x0018 /* SDM */
+#define B43_TXH_PHY1_CRATE             0x0700 /* Coding rate */
+#define  B43_TXH_PHY1_CRATE_1_2                0x0000 /* 1/2 */
+#define  B43_TXH_PHY1_CRATE_2_3                0x0100 /* 2/3 */
+#define  B43_TXH_PHY1_CRATE_3_4                0x0200 /* 3/4 */
+#define  B43_TXH_PHY1_CRATE_4_5                0x0300 /* 4/5 */
+#define  B43_TXH_PHY1_CRATE_5_6                0x0400 /* 5/6 */
+#define  B43_TXH_PHY1_CRATE_7_8                0x0600 /* 7/8 */
+#define B43_TXH_PHY1_MODUL             0x3800 /* Modulation scheme */
+#define  B43_TXH_PHY1_MODUL_BPSK       0x0000 /* BPSK */
+#define  B43_TXH_PHY1_MODUL_QPSK       0x0800 /* QPSK */
+#define  B43_TXH_PHY1_MODUL_QAM16      0x1000 /* QAM16 */
+#define  B43_TXH_PHY1_MODUL_QAM64      0x1800 /* QAM64 */
+#define  B43_TXH_PHY1_MODUL_QAM256     0x2000 /* QAM256 */
+
+
+/* r351 firmware compatibility stuff. */
+static inline
+bool b43_is_old_txhdr_format(struct b43_wldev *dev)
+{
+       return (dev->fw.rev <= 351);
+}
+
+static inline
+size_t b43_txhdr_size(struct b43_wldev *dev)
+{
+       if (b43_is_old_txhdr_format(dev))
+               return 100 + sizeof(struct b43_plcp_hdr6);
+       return 104 + sizeof(struct b43_plcp_hdr6);
+}
+
+
+int b43_generate_txhdr(struct b43_wldev *dev,
+                      u8 * txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+                      const struct ieee80211_tx_control *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
@@ -142,49 +234,56 @@ struct b43_rxhdr_fw4 {
 } __attribute__ ((__packed__));
 
 /* PHY RX Status 0 */
-#define B43_RX_PHYST0_GAINCTL  0x4000  /* Gain Control */
-#define B43_RX_PHYST0_PLCPHCF  0x0200
-#define B43_RX_PHYST0_PLCPFV   0x0100
-#define B43_RX_PHYST0_SHORTPRMBL       0x0080  /* Received with Short Preamble */
+#define B43_RX_PHYST0_GAINCTL          0x4000 /* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF          0x0200
+#define B43_RX_PHYST0_PLCPFV           0x0100
+#define B43_RX_PHYST0_SHORTPRMBL       0x0080 /* Received with Short Preamble */
 #define B43_RX_PHYST0_LCRS             0x0040
-#define B43_RX_PHYST0_ANT              0x0020  /* Antenna */
-#define B43_RX_PHYST0_UNSRATE  0x0010
+#define B43_RX_PHYST0_ANT              0x0020 /* Antenna */
+#define B43_RX_PHYST0_UNSRATE          0x0010
 #define B43_RX_PHYST0_CLIP             0x000C
 #define B43_RX_PHYST0_CLIP_SHIFT       2
-#define B43_RX_PHYST0_FTYPE            0x0003  /* Frame type */
-#define  B43_RX_PHYST0_CCK             0x0000  /* Frame type: CCK */
-#define  B43_RX_PHYST0_OFDM            0x0001  /* Frame type: OFDM */
-#define  B43_RX_PHYST0_PRE_N   0x0002  /* Pre-standard N-PHY frame */
-#define  B43_RX_PHYST0_STD_N   0x0003  /* Standard N-PHY frame */
+#define B43_RX_PHYST0_FTYPE            0x0003 /* Frame type */
+#define  B43_RX_PHYST0_CCK             0x0000 /* Frame type: CCK */
+#define  B43_RX_PHYST0_OFDM            0x0001 /* Frame type: OFDM */
+#define  B43_RX_PHYST0_PRE_N           0x0002 /* Pre-standard N-PHY frame */
+#define  B43_RX_PHYST0_STD_N           0x0003 /* Standard N-PHY frame */
 
 /* PHY RX Status 2 */
-#define B43_RX_PHYST2_LNAG             0xC000  /* LNA Gain */
+#define B43_RX_PHYST2_LNAG             0xC000 /* LNA Gain */
 #define B43_RX_PHYST2_LNAG_SHIFT       14
-#define B43_RX_PHYST2_PNAG             0x3C00  /* PNA Gain */
+#define B43_RX_PHYST2_PNAG             0x3C00 /* PNA Gain */
 #define B43_RX_PHYST2_PNAG_SHIFT       10
-#define B43_RX_PHYST2_FOFF             0x03FF  /* F offset */
+#define B43_RX_PHYST2_FOFF             0x03FF /* F offset */
 
 /* PHY RX Status 3 */
-#define B43_RX_PHYST3_DIGG             0x1800  /* DIG Gain */
+#define B43_RX_PHYST3_DIGG             0x1800 /* DIG Gain */
 #define B43_RX_PHYST3_DIGG_SHIFT       11
-#define B43_RX_PHYST3_TRSTATE  0x0400  /* TR state */
+#define B43_RX_PHYST3_TRSTATE          0x0400 /* TR state */
 
 /* MAC RX Status */
-#define B43_RX_MAC_BEACONSENT  0x00008000      /* Beacon send flag */
-#define B43_RX_MAC_KEYIDX              0x000007E0      /* Key index */
-#define B43_RX_MAC_KEYIDX_SHIFT        5
-#define B43_RX_MAC_DECERR              0x00000010      /* Decrypt error */
-#define B43_RX_MAC_DEC         0x00000008      /* Decryption attempted */
-#define B43_RX_MAC_PADDING             0x00000004      /* Pad bytes present */
-#define B43_RX_MAC_RESP                0x00000002      /* Response frame transmitted */
-#define B43_RX_MAC_FCSERR              0x00000001      /* FCS error */
+#define B43_RX_MAC_RXST_VALID          0x01000000 /* PHY RXST valid */
+#define B43_RX_MAC_TKIP_MICERR         0x00100000 /* TKIP MIC error */
+#define B43_RX_MAC_TKIP_MICATT         0x00080000 /* TKIP MIC attempted */
+#define B43_RX_MAC_AGGTYPE             0x00060000 /* Aggregation type */
+#define B43_RX_MAC_AGGTYPE_SHIFT       17
+#define B43_RX_MAC_AMSDU               0x00010000 /* A-MSDU mask */
+#define B43_RX_MAC_BEACONSENT          0x00008000 /* Beacon sent flag */
+#define B43_RX_MAC_KEYIDX              0x000007E0 /* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT                5
+#define B43_RX_MAC_DECERR              0x00000010 /* Decrypt error */
+#define B43_RX_MAC_DEC                 0x00000008 /* Decryption attempted */
+#define B43_RX_MAC_PADDING             0x00000004 /* Pad bytes present */
+#define B43_RX_MAC_RESP                        0x00000002 /* Response frame transmitted */
+#define B43_RX_MAC_FCSERR              0x00000001 /* FCS error */
 
 /* RX channel */
-#define B43_RX_CHAN_GAIN               0xFC00  /* Gain */
-#define B43_RX_CHAN_GAIN_SHIFT 10
-#define B43_RX_CHAN_ID         0x03FC  /* Channel ID */
-#define B43_RX_CHAN_ID_SHIFT   2
-#define B43_RX_CHAN_PHYTYPE            0x0003  /* PHY type */
+#define B43_RX_CHAN_40MHZ              0x1000 /* 40 Mhz channel width */
+#define B43_RX_CHAN_5GHZ               0x0800 /* 5 Ghz band */
+#define B43_RX_CHAN_ID                 0x07F8 /* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT           3
+#define B43_RX_CHAN_PHYTYPE            0x0007 /* PHY type */
+
 
 u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
 u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
index 700217dada5405f946a2eb885a32b94da132eba3..f383e116cd92fe22524d64769f2b509a4cffbb41 100644 (file)
@@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
 #CONFIG_DRIVER_PRISM54=y
 
 # Driver interface for drivers using Devicescape IEEE 802.11 stack
-CONFIG_DRIVER_DEVICESCAPE=y
+#CONFIG_DRIVER_DEVICESCAPE=y
 # Currently, driver_devicescape.c build requires some additional parameters
 # to be able to include some of the kernel header files. Following lines can
 # be used to set these (WIRELESS_DEV must point to the root directory of the
index a2f3f62bba65f97f4a1ec4198ef2c0357061df06..d1ab057ccce7ef1bfce428ec8e62d3405585eaeb 100644 (file)
@@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
 #CONFIG_DRIVER_PRISM54=y
 
 # Driver interface for drivers using Devicescape IEEE 802.11 stack
-CONFIG_DRIVER_DEVICESCAPE=y
+#CONFIG_DRIVER_DEVICESCAPE=y
 # Currently, driver_devicescape.c build requires some additional parameters
 # to be able to include some of the kernel header files. Following lines can
 # be used to set these (WIRELESS_DEV must point to the root directory of the
index 723ba77be5a6c5634501520cc67ae832707b10b7..9d8320e1805ba57f5600ee7c1107314038004072 100644 (file)
@@ -28,11 +28,12 @@ define KernelPackage/mac80211/description
 Linux 802.11 Wireless Networking Stack
 endef
 
-CONFOPTS:=MAC80211 CFG80211 NL80211
+CONFOPTS:=MAC80211 CFG80211 NL80211 MAC80211_RC_DEFAULT_PID MAC80211_RC_PID
 
 BUILDFLAGS:= \
-       $(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) -DCONFIG_MAC80211_RCSIMPLE=1) \
-       $(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS)
+       $(foreach opt,$(CONFOPTS),-DCONFIG_$(opt)) \
+       $(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS) \
+       -D__CONFIG_MAC80211_RC_DEFAULT=pid
 
 MAKE_OPTS:= \
        CROSS_COMPILE="$(TARGET_CROSS)" \
@@ -40,7 +41,7 @@ MAKE_OPTS:= \
        EXTRA_CFLAGS="$(BUILDFLAGS)" \
        $(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \
        CONFIG_NL80211=y \
-       CONFIG_MAC80211_RCSIMPLE=y \
+       CONFIG_MAC80211_RC_PID=y \
        CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \
        LINUXINCLUDE="-I$(PKG_BUILD_DIR)/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \
 
diff --git a/package/mac80211/patches/000-mac80211_update.patch b/package/mac80211/patches/000-mac80211_update.patch
deleted file mode 100644 (file)
index 7a1a1e2..0000000
+++ /dev/null
@@ -1,933 +0,0 @@
-Index: mac80211/include/linux/ieee80211.h
-===================================================================
---- mac80211.orig/include/linux/ieee80211.h    2007-11-11 15:45:23.153490050 +0100
-+++ mac80211/include/linux/ieee80211.h 2007-11-11 15:45:30.417904025 +0100
-@@ -81,18 +81,18 @@
- /* miscellaneous IEEE 802.11 constants */
--#define IEEE80211_MAX_FRAG_THRESHOLD  2346
--#define IEEE80211_MAX_RTS_THRESHOLD   2347
-+#define IEEE80211_MAX_FRAG_THRESHOLD  2352
-+#define IEEE80211_MAX_RTS_THRESHOLD   2353
- #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) */
-+   802.11e clarifies the figure in section 7.1.2. The frame body is
-+   up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
-+#define IEEE80211_MAX_DATA_LEN                2304
-+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
-+#define IEEE80211_MAX_FRAME_LEN               2352
- #define IEEE80211_MAX_SSID_LEN                32
-Index: mac80211/include/linux/nl80211.h
-===================================================================
---- mac80211.orig/include/linux/nl80211.h      2007-11-11 15:45:23.161490506 +0100
-+++ mac80211/include/linux/nl80211.h   2007-11-11 15:45:30.421904255 +0100
-@@ -25,7 +25,7 @@
-  *    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_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
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h       2007-11-11 15:45:23.169490961 +0100
-+++ mac80211/include/net/mac80211.h    2007-11-11 15:45:30.429904707 +0100
-@@ -706,11 +706,16 @@
-  *
-  * @queues: number of available hardware transmit queues for
-  *    data packets. WMM/QoS requires at least four.
-+ *
-+ * @rate_control_algorithm: rate control algorithm for this hardware.
-+ *    If unset (NULL), the default algorithm will be used. Must be
-+ *    set before calling ieee80211_register_hw().
-  */
- struct ieee80211_hw {
-       struct ieee80211_conf conf;
-       struct wiphy *wiphy;
-       struct workqueue_struct *workqueue;
-+      const char *rate_control_algorithm;
-       void *priv;
-       u32 flags;
-       unsigned int extra_tx_headroom;
-@@ -936,27 +941,11 @@
-  *    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.
-@@ -1029,14 +1018,9 @@
-       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);
-Index: mac80211/net/mac80211/aes_ccm.c
-===================================================================
---- mac80211.orig/net/mac80211/aes_ccm.c       2007-11-11 15:45:23.177491419 +0100
-+++ mac80211/net/mac80211/aes_ccm.c    2007-11-11 15:45:30.433904936 +0100
-@@ -7,10 +7,10 @@
-  * published by the Free Software Foundation.
-  */
-+#include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/crypto.h>
- #include <linux/err.h>
--#include <asm/scatterlist.h>
- #include <net/mac80211.h>
- #include "ieee80211_key.h"
-@@ -63,7 +63,7 @@
-       s_0 = scratch + AES_BLOCK_LEN;
-       e = scratch + 2 * AES_BLOCK_LEN;
--      num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
-+      num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
-       last_len = data_len % AES_BLOCK_LEN;
-       aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
-@@ -102,7 +102,7 @@
-       s_0 = scratch + AES_BLOCK_LEN;
-       a = scratch + 2 * AES_BLOCK_LEN;
--      num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
-+      num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
-       last_len = data_len % AES_BLOCK_LEN;
-       aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
-Index: mac80211/net/mac80211/ieee80211.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211.c     2007-11-11 15:45:23.185491871 +0100
-+++ mac80211/net/mac80211/ieee80211.c  2007-11-11 15:45:30.437905164 +0100
-@@ -1061,7 +1061,8 @@
-       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);
-+      result = ieee80211_init_rate_ctrl_alg(local,
-+                                            hw->rate_control_algorithm);
-       if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
-@@ -1222,8 +1223,17 @@
-       BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+      ret = ieee80211_rate_control_register(&mac80211_rcsimple);
-+      if (ret)
-+              return ret;
-+#endif
-+
-       ret = ieee80211_wme_register();
-       if (ret) {
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+              ieee80211_rate_control_unregister(&mac80211_rcsimple);
-+#endif
-               printk(KERN_DEBUG "ieee80211_init: failed to "
-                      "initialize WME (err=%d)\n", ret);
-               return ret;
-@@ -1237,6 +1247,10 @@
- static void __exit ieee80211_exit(void)
- {
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+      ieee80211_rate_control_unregister(&mac80211_rcsimple);
-+#endif
-+
-       ieee80211_wme_unregister();
-       ieee80211_debugfs_netdev_exit();
- }
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h   2007-11-11 15:45:23.189492100 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h        2007-11-11 15:45:30.441905395 +0100
-@@ -232,6 +232,7 @@
- #define IEEE80211_STA_AUTO_SSID_SEL   BIT(10)
- #define IEEE80211_STA_AUTO_BSSID_SEL  BIT(11)
- #define IEEE80211_STA_AUTO_CHANNEL_SEL        BIT(12)
-+#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
- struct ieee80211_if_sta {
-       enum {
-               IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-@@ -261,7 +262,6 @@
-       unsigned long request;
-       struct sk_buff_head skb_queue;
--      int key_management_enabled;
-       unsigned long last_probe;
- #define IEEE80211_AUTH_ALG_OPEN BIT(0)
-Index: mac80211/net/mac80211/ieee80211_ioctl.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_ioctl.c       2007-11-11 15:45:23.197492559 +0100
-+++ mac80211/net/mac80211/ieee80211_ioctl.c    2007-11-11 15:45:30.441905395 +0100
-@@ -305,9 +305,12 @@
-                           ((chan->chan == channel) || (chan->freq == freq))) {
-                               local->oper_channel = chan;
-                               local->oper_hw_mode = mode;
--                              set++;
-+                              set = 1;
-+                              break;
-                       }
-               }
-+              if (set)
-+                      break;
-       }
-       if (set) {
-@@ -507,10 +510,11 @@
- static int ieee80211_ioctl_siwscan(struct net_device *dev,
-                                  struct iw_request_info *info,
--                                 struct iw_point *data, char *extra)
-+                                 union iwreq_data *wrqu, char *extra)
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct iw_scan_req *req = NULL;
-       u8 *ssid = NULL;
-       size_t ssid_len = 0;
-@@ -535,6 +539,14 @@
-               return -EOPNOTSUPP;
-       }
-+      /* if SSID was specified explicitly then use that */
-+      if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-+          wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-+              req = (struct iw_scan_req *)extra;
-+              ssid = req->essid;
-+              ssid_len = req->essid_len;
-+      }
-+
-       return ieee80211_sta_req_scan(dev, ssid, ssid_len);
- }
-@@ -621,22 +633,35 @@
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       bool need_reconfig = 0;
-+      u8 new_power_level;
-       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;
--      if (local->hw.conf.power_level != data->txpower.value) {
--              local->hw.conf.power_level = data->txpower.value;
-+      if (data->txpower.fixed) {
-+              new_power_level = data->txpower.value;
-+      } else {
-+              /* Automatic power level. Get the px power from the current
-+               * channel. */
-+              struct ieee80211_channel* chan = local->oper_channel;
-+              if (!chan)
-+                      return -EINVAL;
-+
-+              new_power_level = chan->power_level;
-+      }
-+
-+      if (local->hw.conf.power_level != new_power_level) {
-+              local->hw.conf.power_level = new_power_level;
-               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,
-@@ -904,7 +929,6 @@
-                                  struct iw_request_info *info,
-                                  struct iw_param *data, char *extra)
- {
--      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       int ret = 0;
-@@ -914,18 +938,21 @@
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_WPA_ENABLED:
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
--              break;
-       case IW_AUTH_KEY_MGMT:
-+              break;
-+      case IW_AUTH_PRIVACY_INVOKED:
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
-                       ret = -EINVAL;
-               else {
-+                      sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
-                       /*
--                       * 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.
-+                       * Privacy invoked by wpa_supplicant, store the
-+                       * value and allow associating to a protected
-+                       * network without having a key up front.
-                        */
--                      sdata->u.sta.key_management_enabled = !!data->value;
-+                      if (data->value)
-+                              sdata->u.sta.flags |=
-+                                      IEEE80211_STA_PRIVACY_INVOKED;
-               }
-               break;
-       case IW_AUTH_80211_AUTH_ALG:
-@@ -935,11 +962,6 @@
-               else
-                       ret = -EOPNOTSUPP;
-               break;
--      case IW_AUTH_PRIVACY_INVOKED:
--              if (local->ops->set_privacy_invoked)
--                      ret = local->ops->set_privacy_invoked(
--                                      local_to_hw(local), data->value);
--              break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-Index: mac80211/net/mac80211/ieee80211_rate.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.c        2007-11-11 15:45:23.205493011 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.c     2007-11-11 15:45:30.441905395 +0100
-@@ -25,13 +25,25 @@
- {
-       struct rate_control_alg *alg;
-+      if (!ops->name)
-+              return -EINVAL;
-+
-+      mutex_lock(&rate_ctrl_mutex);
-+      list_for_each_entry(alg, &rate_ctrl_algs, list) {
-+              if (!strcmp(alg->ops->name, ops->name)) {
-+                      /* don't register an algorithm twice */
-+                      WARN_ON(1);
-+                      return -EALREADY;
-+              }
-+      }
-+
-       alg = kzalloc(sizeof(*alg), GFP_KERNEL);
-       if (alg == NULL) {
-+              mutex_unlock(&rate_ctrl_mutex);
-               return -ENOMEM;
-       }
-       alg->ops = ops;
--      mutex_lock(&rate_ctrl_mutex);
-       list_add_tail(&alg->list, &rate_ctrl_algs);
-       mutex_unlock(&rate_ctrl_mutex);
-@@ -61,9 +73,12 @@
-       struct rate_control_alg *alg;
-       struct rate_control_ops *ops = NULL;
-+      if (!name)
-+              return NULL;
-+
-       mutex_lock(&rate_ctrl_mutex);
-       list_for_each_entry(alg, &rate_ctrl_algs, list) {
--              if (!name || !strcmp(alg->ops->name, name))
-+              if (!strcmp(alg->ops->name, name))
-                       if (try_module_get(alg->ops->module)) {
-                               ops = alg->ops;
-                               break;
-@@ -80,9 +95,12 @@
- {
-       struct rate_control_ops *ops;
-+      if (!name)
-+              name = "simple";
-+
-       ops = ieee80211_try_rate_control_ops_get(name);
-       if (!ops) {
--              request_module("rc80211_%s", name ? name : "default");
-+              request_module("rc80211_%s", name);
-               ops = ieee80211_try_rate_control_ops_get(name);
-       }
-       return ops;
-Index: mac80211/net/mac80211/ieee80211_rate.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.h        2007-11-11 15:45:23.213493469 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.h     2007-11-11 15:45:30.445905621 +0100
-@@ -65,6 +65,9 @@
-       struct kref kref;
- };
-+/* default 'simple' algorithm */
-+extern struct rate_control_ops mac80211_rcsimple;
-+
- int ieee80211_rate_control_register(struct rate_control_ops *ops);
- void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
-Index: mac80211/net/mac80211/ieee80211_sta.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:45:23.217493699 +0100
-+++ mac80211/net/mac80211/ieee80211_sta.c      2007-11-11 15:46:32.885463850 +0100
-@@ -12,7 +12,6 @@
-  */
- /* TODO:
-- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
-  * order BSS list by RSSI(?) ("quality of AP")
-  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
-  *    SSID)
-@@ -61,7 +60,8 @@
- static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
-                                    u8 *ssid, size_t ssid_len);
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
-+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
-+                   u8 *ssid, u8 ssid_len);
- static void ieee80211_rx_bss_put(struct net_device *dev,
-                                struct ieee80211_sta_bss *bss);
- static int ieee80211_sta_find_ibss(struct net_device *dev,
-@@ -108,14 +108,11 @@
-       u8 wmm_param_len;
- };
--enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
--
--static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
--                                          struct ieee802_11_elems *elems)
-+static void ieee802_11_parse_elems(u8 *start, size_t len,
-+                                 struct ieee802_11_elems *elems)
- {
-       size_t left = len;
-       u8 *pos = start;
--      int unknown = 0;
-       memset(elems, 0, sizeof(*elems));
-@@ -126,15 +123,8 @@
-               elen = *pos++;
-               left -= 2;
--              if (elen > left) {
--#if 0
--                      if (net_ratelimit())
--                              printk(KERN_DEBUG "IEEE 802.11 element parse "
--                                     "failed (id=%d elen=%d left=%d)\n",
--                                     id, elen, left);
--#endif
--                      return ParseFailed;
--              }
-+              if (elen > left)
-+                      return;
-               switch (id) {
-               case WLAN_EID_SSID:
-@@ -201,28 +191,15 @@
-                       elems->ext_supp_rates_len = elen;
-                       break;
-               default:
--#if 0
--                      printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
--                                    "unknown element (id=%d elen=%d)\n",
--                                    id, elen);
--#endif
--                      unknown++;
-                       break;
-               }
-               left -= elen;
-               pos += elen;
-       }
--
--      /* Do not trigger error if left == 1 as Apple Airport base stations
--       * send AssocResps that are one spurious byte too long. */
--
--      return unknown ? ParseUnknown : ParseOK;
- }
--
--
- static int ecw2cw(int ecw)
- {
-       int cw = 1;
-@@ -426,7 +403,9 @@
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
-                       return;
--              bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+              bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-+                                         local->hw.conf.channel,
-+                                         ifsta->ssid, ifsta->ssid_len);
-               if (bss) {
-                       if (bss->has_erp_value)
-                               ieee80211_handle_erp_ie(dev, bss->erp_value);
-@@ -571,7 +550,8 @@
-               capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-                       WLAN_CAPABILITY_SHORT_PREAMBLE;
-       }
--      bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+      bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
-+                                 ifsta->ssid, ifsta->ssid_len);
-       if (bss) {
-               if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-                       capab |= WLAN_CAPABILITY_PRIVACY;
-@@ -719,24 +699,30 @@
- static int ieee80211_privacy_mismatch(struct net_device *dev,
-                                     struct ieee80211_if_sta *ifsta)
- {
-+      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sta_bss *bss;
--      int res = 0;
-+      int bss_privacy;
-+      int wep_privacy;
-+      int privacy_invoked;
--      if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
--          ifsta->key_management_enabled)
-+      if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
-               return 0;
--      bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+      bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
-+                                 ifsta->ssid, ifsta->ssid_len);
-       if (!bss)
-               return 0;
--      if (ieee80211_sta_wep_configured(dev) !=
--          !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
--              res = 1;
-+      bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
-+      wep_privacy = !!ieee80211_sta_wep_configured(dev);
-+      privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
-       ieee80211_rx_bss_put(dev, bss);
--      return res;
-+      if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
-+              return 0;
-+
-+      return 1;
- }
-@@ -920,12 +906,7 @@
-       printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
-       pos = mgmt->u.auth.variable;
--      if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
--          == ParseFailed) {
--              printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
--                     dev->name);
--              return;
--      }
-+      ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-       if (!elems.challenge) {
-               printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
-                      "frame\n", dev->name);
-@@ -1214,12 +1195,7 @@
-       }
-       pos = mgmt->u.assoc_resp.variable;
--      if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
--          == ParseFailed) {
--              printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
--                     dev->name);
--              return;
--      }
-+      ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-       if (!elems.supp_rates) {
-               printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-@@ -1231,7 +1207,9 @@
-        * 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);
-+                      = ieee80211_rx_bss_get(dev, ifsta->bssid,
-+                                             local->hw.conf.channel,
-+                                             ifsta->ssid, ifsta->ssid_len);
-               if (bss) {
-                       bss->erp_value = elems.erp_info[0];
-                       bss->has_erp_value = 1;
-@@ -1261,7 +1239,9 @@
-                              " AP\n", dev->name);
-                       return;
-               }
--              bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+              bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-+                                         local->hw.conf.channel,
-+                                         ifsta->ssid, ifsta->ssid_len);
-               if (bss) {
-                       sta->last_rssi = bss->rssi;
-                       sta->last_signal = bss->signal;
-@@ -1337,7 +1317,8 @@
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
-+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
-+                   u8 *ssid, u8 ssid_len)
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sta_bss *bss;
-@@ -1348,6 +1329,11 @@
-       atomic_inc(&bss->users);
-       atomic_inc(&bss->users);
-       memcpy(bss->bssid, bssid, ETH_ALEN);
-+      bss->channel = channel;
-+      if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
-+              memcpy(bss->ssid, ssid, ssid_len);
-+              bss->ssid_len = ssid_len;
-+      }
-       spin_lock_bh(&local->sta_bss_lock);
-       /* TODO: order by RSSI? */
-@@ -1359,7 +1345,8 @@
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
-+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
-+                   u8 *ssid, u8 ssid_len)
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sta_bss *bss;
-@@ -1367,7 +1354,10 @@
-       spin_lock_bh(&local->sta_bss_lock);
-       bss = local->sta_bss_hash[STA_HASH(bssid)];
-       while (bss) {
--              if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
-+              if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
-+                  bss->channel == channel &&
-+                  bss->ssid_len == ssid_len &&
-+                  (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
-                       atomic_inc(&bss->users);
-                       break;
-               }
-@@ -1429,7 +1419,7 @@
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee802_11_elems elems;
-       size_t baselen;
--      int channel, invalid = 0, clen;
-+      int channel, clen;
-       struct ieee80211_sta_bss *bss;
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -1473,9 +1463,7 @@
- #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-       }
--      if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
--                                 &elems) == ParseFailed)
--              invalid = 1;
-+      ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
-           memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
-@@ -1533,9 +1521,11 @@
-       else
-               channel = rx_status->channel;
--      bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
-+      bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel,
-+                                 elems.ssid, elems.ssid_len);
-       if (!bss) {
--              bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
-+              bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel,
-+                                         elems.ssid, elems.ssid_len);
-               if (!bss)
-                       return;
-       } else {
-@@ -1561,10 +1551,6 @@
-       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) {
--              memcpy(bss->ssid, elems.ssid, elems.ssid_len);
--              bss->ssid_len = elems.ssid_len;
--      }
-       bss->supp_rates_len = 0;
-       if (elems.supp_rates) {
-@@ -1635,7 +1621,6 @@
-       bss->hw_mode = rx_status->phymode;
--      bss->channel = channel;
-       bss->freq = rx_status->freq;
-       if (channel != rx_status->channel &&
-           (bss->hw_mode == MODE_IEEE80211G ||
-@@ -1695,9 +1680,7 @@
-       if (baselen > len)
-               return;
--      if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
--                                 &elems) == ParseFailed)
--              return;
-+      ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-       if (elems.erp_info && elems.erp_info_len >= 1)
-               ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
-@@ -2098,7 +2081,8 @@
- {
-       int tmp, hidden_ssid;
--      if (!memcmp(ifsta->ssid, ssid, ssid_len))
-+      if (ssid_len == ifsta->ssid_len &&
-+          !memcmp(ifsta->ssid, ssid, ssid_len))
-               return 1;
-       if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
-@@ -2357,7 +2341,7 @@
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sta_bss *bss;
--      struct ieee80211_sub_if_data *sdata;
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_hw_mode *mode;
-       u8 bssid[ETH_ALEN], *pos;
-       int i;
-@@ -2379,18 +2363,17 @@
-       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
-              dev->name, MAC_ARG(bssid));
--      bss = ieee80211_rx_bss_add(dev, bssid);
-+      bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel,
-+                                 sdata->u.sta.ssid, sdata->u.sta.ssid_len);
-       if (!bss)
-               return -ENOMEM;
--      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       mode = local->oper_hw_mode;
-       if (local->hw.conf.beacon_int == 0)
-               local->hw.conf.beacon_int = 100;
-       bss->beacon_int = local->hw.conf.beacon_int;
-       bss->hw_mode = local->hw.conf.phymode;
--      bss->channel = local->hw.conf.channel;
-       bss->freq = local->hw.conf.freq;
-       bss->last_update = jiffies;
-       bss->capability = WLAN_CAPABILITY_IBSS;
-@@ -2448,7 +2431,8 @@
-              MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
- #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-       if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
--          (bss = ieee80211_rx_bss_get(dev, bssid))) {
-+          (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel,
-+                                      ifsta->ssid, ifsta->ssid_len))) {
-               printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
-                      " based on configured SSID\n",
-                      dev->name, MAC_ARG(bssid));
-Index: mac80211/net/mac80211/Kconfig
-===================================================================
---- mac80211.orig/net/mac80211/Kconfig 2007-11-11 15:45:23.225494151 +0100
-+++ mac80211/net/mac80211/Kconfig      2007-11-11 15:45:30.449905846 +0100
-@@ -13,6 +13,18 @@
-       This option enables the hardware independent IEEE 802.11
-       networking stack.
-+config MAC80211_RCSIMPLE
-+      bool "'simple' rate control algorithm" if EMBEDDED
-+      default y
-+      depends on MAC80211
-+      help
-+        This option allows you to turn off the 'simple' rate
-+        control algorithm in mac80211. If you do turn it off,
-+        you absolutely need another rate control algorithm.
-+
-+        Say Y unless you know you will have another algorithm
-+        available.
-+
- config MAC80211_LEDS
-       bool "Enable LED triggers"
-       depends on MAC80211 && LEDS_TRIGGERS
-Index: mac80211/net/mac80211/Makefile
-===================================================================
---- mac80211.orig/net/mac80211/Makefile        2007-11-11 15:45:23.233494609 +0100
-+++ mac80211/net/mac80211/Makefile     2007-11-11 15:45:30.449905846 +0100
-@@ -1,8 +1,9 @@
--obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
-+obj-$(CONFIG_MAC80211) += mac80211.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-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o
- mac80211-objs := \
-       ieee80211.o \
-Index: mac80211/net/mac80211/rc80211_simple.c
-===================================================================
---- mac80211.orig/net/mac80211/rc80211_simple.c        2007-11-11 15:45:23.237494839 +0100
-+++ mac80211/net/mac80211/rc80211_simple.c     2007-11-11 15:45:30.449905846 +0100
-@@ -7,7 +7,6 @@
-  * published by the Free Software Foundation.
-  */
--#include <linux/module.h>
- #include <linux/init.h>
- #include <linux/netdevice.h>
- #include <linux/types.h>
-@@ -29,8 +28,6 @@
- #define RATE_CONTROL_INTERVAL (HZ / 20)
- #define RATE_CONTROL_MIN_TX 10
--MODULE_ALIAS("rc80211_default");
--
- static void rate_control_rate_inc(struct ieee80211_local *local,
-                                 struct sta_info *sta)
- {
-@@ -393,8 +390,7 @@
- }
- #endif
--static struct rate_control_ops rate_control_simple = {
--      .module = THIS_MODULE,
-+struct rate_control_ops mac80211_rcsimple = {
-       .name = "simple",
-       .tx_status = rate_control_simple_tx_status,
-       .get_rate = rate_control_simple_get_rate,
-@@ -409,22 +405,3 @@
-       .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
- #endif
- };
--
--
--static int __init rate_control_simple_init(void)
--{
--      return ieee80211_rate_control_register(&rate_control_simple);
--}
--
--
--static void __exit rate_control_simple_exit(void)
--{
--      ieee80211_rate_control_unregister(&rate_control_simple);
--}
--
--
--subsys_initcall(rate_control_simple_init);
--module_exit(rate_control_simple_exit);
--
--MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
--MODULE_LICENSE("GPL");
-Index: mac80211/net/mac80211/rx.c
-===================================================================
---- mac80211.orig/net/mac80211/rx.c    2007-11-11 15:45:23.245495291 +0100
-+++ mac80211/net/mac80211/rx.c 2007-11-11 15:45:30.449905846 +0100
-@@ -509,9 +509,11 @@
-               rx->key->tx_rx_count++;
-               /* TODO: add threshold stuff again */
-       } else {
-+#ifdef CONFIG_MAC80211_DEBUG
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "%s: RX protected frame,"
-                              " but have no key\n", rx->dev->name);
-+#endif /* CONFIG_MAC80211_DEBUG */
-               return TXRX_DROP;
-       }
-Index: mac80211/net/mac80211/wep.c
-===================================================================
---- mac80211.orig/net/mac80211/wep.c   2007-11-11 15:45:23.253495749 +0100
-+++ mac80211/net/mac80211/wep.c        2007-11-11 15:45:30.449905846 +0100
-@@ -16,7 +16,7 @@
- #include <linux/crypto.h>
- #include <linux/err.h>
- #include <linux/mm.h>
--#include <asm/scatterlist.h>
-+#include <linux/scatterlist.h>
- #include <net/mac80211.h>
- #include "ieee80211_i.h"
-@@ -138,9 +138,7 @@
-       *icv = cpu_to_le32(~crc32_le(~0, data, data_len));
-       crypto_blkcipher_setkey(tfm, rc4key, klen);
--      sg.page = virt_to_page(data);
--      sg.offset = offset_in_page(data);
--      sg.length = data_len + WEP_ICV_LEN;
-+      sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
-       crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
- }
-@@ -204,9 +202,7 @@
-       __le32 crc;
-       crypto_blkcipher_setkey(tfm, rc4key, klen);
--      sg.page = virt_to_page(data);
--      sg.offset = offset_in_page(data);
--      sg.length = data_len + WEP_ICV_LEN;
-+      sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
-       crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
-       crc = cpu_to_le32(~crc32_le(~0, data, data_len));
-@@ -318,9 +314,11 @@
-       if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
-               if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
-+#ifdef CONFIG_MAC80211_DEBUG
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
-                                      "failed\n", rx->dev->name);
-+#endif /* CONFIG_MAC80211_DEBUG */
-                       return TXRX_DROP;
-               }
-       } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
-Index: mac80211/net/wireless/Kconfig
-===================================================================
---- mac80211.orig/net/wireless/Kconfig 2007-11-11 15:45:23.261496205 +0100
-+++ mac80211/net/wireless/Kconfig      2007-11-11 15:45:30.453906075 +0100
-@@ -3,7 +3,7 @@
- config NL80211
-       bool "nl80211 new netlink interface support"
--      depends CFG80211
-+      depends on CFG80211
-       default y
-       ---help---
-          This option turns on the new netlink interface
diff --git a/package/mac80211/patches/001-port-to-2.6.23.patch b/package/mac80211/patches/001-port-to-2.6.23.patch
new file mode 100644 (file)
index 0000000..2e88d40
--- /dev/null
@@ -0,0 +1,231 @@
+Index: mac80211/net/mac80211/ieee80211.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211.c     2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211.c  2008-02-15 22:21:01.000000000 +0100
+@@ -21,7 +21,6 @@
+ #include <linux/wireless.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/bitmap.h>
+-#include <net/net_namespace.h>
+ #include <net/cfg80211.h>
+ #include "ieee80211_i.h"
+@@ -36,6 +35,15 @@
+ #define SUPP_MCS_SET_LEN 16
++
++char *print_mac(char *buf, const u8 *addr)
++{
++      sprintf(buf, MAC_FMT,
++              addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
++      return buf;
++}
++
++
+ /*
+  * For seeing transmitted packets on monitor interfaces
+  * we have a radiotap header too.
+@@ -48,11 +56,13 @@ struct ieee80211_tx_status_rtap_hdr {
+ /* common interface routines */
++#if 0
+ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
+ {
+       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+       return ETH_ALEN;
+ }
++#endif
+ /* must be called under mdev tx lock */
+ static void ieee80211_configure_filter(struct ieee80211_local *local)
+@@ -800,6 +810,7 @@ static void ieee80211_set_multicast_list
+       dev_mc_sync(local->mdev, dev);
+ }
++#if 0
+ static const struct header_ops ieee80211_header_ops = {
+       .create         = eth_header,
+       .parse          = header_parse_80211,
+@@ -807,6 +818,7 @@ static const struct header_ops ieee80211
+       .cache          = eth_header_cache,
+       .cache_update   = eth_header_cache_update,
+ };
++#endif
+ /* Must not be called for mdev */
+ void ieee80211_if_setup(struct net_device *dev)
+@@ -1455,7 +1467,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+       mdev->open = ieee80211_master_open;
+       mdev->stop = ieee80211_master_stop;
+       mdev->type = ARPHRD_IEEE80211;
+-      mdev->header_ops = &ieee80211_header_ops;
++//    mdev->header_ops = &ieee80211_header_ops;
+       mdev->set_multicast_list = ieee80211_master_set_multicast_list;
+       sdata->vif.type = IEEE80211_IF_TYPE_AP;
+Index: mac80211/net/mac80211/ieee80211_i.h
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_i.h   2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211_i.h        2008-02-15 22:21:37.000000000 +0100
+@@ -26,6 +26,16 @@
+ #include "ieee80211_key.h"
+ #include "sta_info.h"
++
++#define BIT(nr)               (1 << (nr))
++
++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
++extern char *print_mac(char *buf, const u8 *addr);
++#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
++
++#define CONFIG_MAC80211_RC_DEFAULT    __stringify(__CONFIG_MAC80211_RC_DEFAULT)
++
++
+ /* ieee80211.o internal definitions, etc. These are not included into
+  * low-level drivers. */
+Index: mac80211/net/mac80211/ieee80211_ioctl.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_ioctl.c       2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211_ioctl.c    2008-02-15 22:21:01.000000000 +0100
+@@ -207,7 +207,7 @@ static int ieee80211_ioctl_giwrange(stru
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+-      range->scan_capa |= IW_SCAN_CAPA_ESSID;
++//    range->scan_capa |= IW_SCAN_CAPA_ESSID;
+       return 0;
+ }
+Index: mac80211/net/wireless/core.c
+===================================================================
+--- mac80211.orig/net/wireless/core.c  2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/core.c       2008-02-15 22:21:01.000000000 +0100
+@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_inf
+       if (info->attrs[NL80211_ATTR_IFINDEX]) {
+               ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+-              dev = dev_get_by_index(&init_net, ifindex);
++              dev = dev_get_by_index(ifindex);
+               if (dev) {
+                       if (dev->ieee80211_ptr)
+                               byifidx =
+@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifinde
+       struct net_device *dev;
+       mutex_lock(&cfg80211_drv_mutex);
+-      dev = dev_get_by_index(&init_net, ifindex);
++      dev = dev_get_by_index(ifindex);
+       if (!dev)
+               goto out;
+       if (dev->ieee80211_ptr) {
+Index: mac80211/net/wireless/nl80211.c
+===================================================================
+--- mac80211.orig/net/wireless/nl80211.c       2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/nl80211.c    2008-02-15 22:21:01.000000000 +0100
+@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(s
+               return -EINVAL;
+       ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+-      *dev = dev_get_by_index(&init_net, ifindex);
++      *dev = dev_get_by_index(ifindex);
+       if (!*dev)
+               return -ENODEV;
+@@ -959,7 +959,7 @@ static int get_vlan(struct nlattr *vlana
+       *vlan = NULL;
+       if (vlanattr) {
+-              *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
++              *vlan = dev_get_by_index(nla_get_u32(vlanattr));
+               if (!*vlan)
+                       return -ENODEV;
+               if (!(*vlan)->ieee80211_ptr)
+Index: mac80211/net/mac80211/cfg.c
+===================================================================
+--- mac80211.orig/net/mac80211/cfg.c   2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/cfg.c        2008-02-15 22:21:01.000000000 +0100
+@@ -9,7 +9,6 @@
+ #include <linux/ieee80211.h>
+ #include <linux/nl80211.h>
+ #include <linux/rtnetlink.h>
+-#include <net/net_namespace.h>
+ #include <linux/rcupdate.h>
+ #include <net/cfg80211.h>
+ #include "ieee80211_i.h"
+@@ -68,7 +67,7 @@ static int ieee80211_del_iface(struct wi
+               return -ENODEV;
+       /* we're under RTNL */
+-      dev = __dev_get_by_index(&init_net, ifindex);
++      dev = __dev_get_by_index(ifindex);
+       if (!dev)
+               return 0;
+@@ -89,7 +88,7 @@ static int ieee80211_change_iface(struct
+               return -ENODEV;
+       /* we're under RTNL */
+-      dev = __dev_get_by_index(&init_net, ifindex);
++      dev = __dev_get_by_index(ifindex);
+       if (!dev)
+               return -ENODEV;
+Index: mac80211/net/mac80211/tx.c
+===================================================================
+--- mac80211.orig/net/mac80211/tx.c    2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/tx.c 2008-02-15 22:21:01.000000000 +0100
+@@ -18,7 +18,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/bitmap.h>
+ #include <linux/rcupdate.h>
+-#include <net/net_namespace.h>
+ #include <net/ieee80211_radiotap.h>
+ #include <net/cfg80211.h>
+ #include <net/mac80211.h>
+@@ -1051,7 +1050,7 @@ static int ieee80211_tx_prepare(struct i
+       struct net_device *dev;
+       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+-      dev = dev_get_by_index(&init_net, pkt_data->ifindex);
++      dev = dev_get_by_index(pkt_data->ifindex);
+       if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+               dev_put(dev);
+               dev = NULL;
+@@ -1265,7 +1264,7 @@ int ieee80211_master_start_xmit(struct s
+       memset(&control, 0, sizeof(struct ieee80211_tx_control));
+       if (pkt_data->ifindex)
+-              odev = dev_get_by_index(&init_net, pkt_data->ifindex);
++              odev = dev_get_by_index(pkt_data->ifindex);
+       if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+               dev_put(odev);
+               odev = NULL;
+Index: mac80211/net/mac80211/util.c
+===================================================================
+--- mac80211.orig/net/mac80211/util.c  2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/util.c       2008-02-15 22:21:01.000000000 +0100
+@@ -20,7 +20,6 @@
+ #include <linux/if_arp.h>
+ #include <linux/wireless.h>
+ #include <linux/bitmap.h>
+-#include <net/net_namespace.h>
+ #include <net/cfg80211.h>
+ #include <net/rtnetlink.h>
+Index: mac80211/net/wireless/sysfs.c
+===================================================================
+--- mac80211.orig/net/wireless/sysfs.c 2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/sysfs.c      2008-02-15 22:21:01.000000000 +0100
+@@ -53,7 +53,8 @@ static void wiphy_dev_release(struct dev
+ }
+ #ifdef CONFIG_HOTPLUG
+-static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
++static int wiphy_uevent(struct device *dev, char **envp, int num_envp,
++                      char *buffer, int buffer_size)
+ {
+       /* TODO, we probably need stuff here */
+       return 0;
diff --git a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch b/package/mac80211/patches/008-add-hostapd-ioctl-header.patch
deleted file mode 100644 (file)
index acea0ce..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
----
- net/mac80211/hostapd_ioctl.h |  103 +++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 103 insertions(+)
-
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ everything/net/mac80211/hostapd_ioctl.h    2007-11-07 13:19:23.031516330 +0100
-@@ -0,0 +1,103 @@
-+/*
-+ * 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_AP_BRIDGE_PACKETS = 10,
-+      PRISM2_PARAM_IEEE_802_1X = 23,
-+
-+      /* Instant802 additions */
-+      PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
-+      PRISM2_PARAM_PREAMBLE = 1003,
-+      PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
-+      PRISM2_PARAM_NEXT_MODE = 1008,
-+      PRISM2_PARAM_PRIVACY_INVOKED = 1014,
-+      PRISM2_PARAM_EAPOL = 1023,
-+      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,
-+
-+      /* Instant802 additions */
-+      PRISM2_HOSTAPD_GET_HW_FEATURES = 1002,
-+      PRISM2_HOSTAPD_SET_RATE_SETS = 1005,
-+      PRISM2_HOSTAPD_SET_CHANNEL_FLAG = 1012,
-+      PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN = 1013,
-+      PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS = 1014,
-+};
-+
-+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
-+#define ALIGNED __attribute__ ((aligned))
-+
-+struct prism2_hostapd_param {
-+      u32 cmd;
-+      u8 sta_addr[ETH_ALEN];
-+      u8 pad[2];
-+      union {
-+              struct {
-+                      u16 num_modes;
-+                      u16 flags;
-+                      u8 data[0] ALIGNED; /* num_modes * feature data */
-+              } hw_features;
-+              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 {
-+                      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;
-+      } u;
-+};
-+
-+/* Data structures used for get_hw_features ioctl */
-+struct hostapd_ioctl_hw_modes_hdr {
-+      int mode;
-+      int num_channels;
-+      int num_rates;
-+};
-+
-+#endif /* HOSTAPD_IOCTL_H */
diff --git a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch b/package/mac80211/patches/009-add-old-ioctl-skeleton.patch
deleted file mode 100644 (file)
index fb9f25f..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
----
- net/mac80211/ieee80211.c       |    5 +
- net/mac80211/ieee80211_ioctl.c |  121 +++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 126 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:06:34.902124618 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:24.311521482 +0100
-@@ -21,6 +21,7 @@
- #include <net/mac80211.h>
- #include "ieee80211_i.h"
-+#include "hostapd_ioctl.h"
- #include "ieee80211_rate.h"
- #include "wpa.h"
- #include "aes_ccm.h"
-@@ -124,6 +125,47 @@ static int ieee80211_ioctl_siwgenie(stru
-       return -EOPNOTSUPP;
- }
-+
-+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 = 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) {
-+      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)
-@@ -819,6 +861,49 @@ static int ieee80211_ioctl_giwretry(stru
-       return 0;
- }
-+static int ieee80211_ioctl_prism2_param(struct net_device *dev,
-+                                      struct iw_request_info *info,
-+                                      void *wrqu, char *extra)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+      int *i = (int *) extra;
-+      int param = *i;
-+      int ret = 0;
-+
-+      if (!capable(CAP_NET_ADMIN))
-+              return -EPERM;
-+
-+      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      switch (param) {
-+      default:
-+              ret = -EOPNOTSUPP;
-+              break;
-+      }
-+
-+      return ret;
-+}
-+
-+
-+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
-+                                          struct iw_request_info *info,
-+                                          void *wrqu, char *extra)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+      int *param = (int *) extra;
-+      int ret = 0;
-+
-+      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      switch (*param) {
-+      default:
-+              ret = -EOPNOTSUPP;
-+              break;
-+      }
-+
-+      return ret;
-+}
-+
- static int ieee80211_ioctl_siwmlme(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_point *data, char *extra)
-@@ -1073,6 +1158,32 @@ static int ieee80211_ioctl_siwencodeext(
- }
-+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;
-+
-+      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))
-+                      return -EPERM;
-+              return ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data);
-+      default:
-+              return -EOPNOTSUPP;
-+      }
-+}
-+
-+
- /* Structures to export the Wireless Handlers */
- static const iw_handler ieee80211_handler[] =
-@@ -1135,9 +1246,19 @@ static const iw_handler ieee80211_handle
-       (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,
- };
---- everything.orig/net/mac80211/ieee80211.c   2007-11-07 13:18:36.001511500 +0100
-+++ everything/net/mac80211/ieee80211.c        2007-11-07 13:19:24.311521482 +0100
-@@ -413,6 +413,9 @@ static const struct header_ops ieee80211
-       .cache_update   = eth_header_cache_update,
- };
-+/* HACK */
-+extern int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+
- /* Must not be called for mdev */
- void ieee80211_if_setup(struct net_device *dev)
- {
-@@ -425,6 +428,8 @@ void ieee80211_if_setup(struct net_devic
-       dev->open = ieee80211_open;
-       dev->stop = ieee80211_stop;
-       dev->destructor = ieee80211_if_free;
-+
-+      dev->do_ioctl = ieee80211_ioctl;
- }
- /* WDS specialties */
diff --git a/package/mac80211/patches/010-add-mgmt-iface.patch b/package/mac80211/patches/010-add-mgmt-iface.patch
deleted file mode 100644 (file)
index eae5ff6..0000000
+++ /dev/null
@@ -1,688 +0,0 @@
----
- include/net/mac80211.h          |    1 
- net/mac80211/ieee80211.c        |  198 ++++++++++++++++++++++++++++++++++++++--
- net/mac80211/ieee80211_common.h |   64 ++++++++++++
- net/mac80211/ieee80211_i.h      |    9 +
- net/mac80211/ieee80211_iface.c  |   66 +++++++++++++
- net/mac80211/ieee80211_ioctl.c  |   21 ++++
- net/mac80211/ieee80211_rate.c   |    3 
- net/mac80211/ieee80211_rate.h   |    2 
- net/mac80211/ieee80211_sta.c    |    2 
- net/mac80211/rx.c               |   29 ++++-
- net/mac80211/tx.c               |   14 ++
- net/mac80211/wme.c              |   10 +-
- 12 files changed, 399 insertions(+), 20 deletions(-)
-
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h       2007-11-11 15:15:42.824034853 +0100
-+++ mac80211/include/net/mac80211.h    2007-11-11 15:15:53.784659457 +0100
-@@ -472,6 +472,7 @@
- enum ieee80211_if_types {
-       IEEE80211_IF_TYPE_INVALID,
-       IEEE80211_IF_TYPE_AP,
-+      IEEE80211_IF_TYPE_MGMT,
-       IEEE80211_IF_TYPE_STA,
-       IEEE80211_IF_TYPE_IBSS,
-       IEEE80211_IF_TYPE_MNTR,
-Index: mac80211/net/mac80211/ieee80211.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211.c     2007-11-11 15:15:51.536531354 +0100
-+++ mac80211/net/mac80211/ieee80211.c  2007-11-11 15:16:22.214279577 +0100
-@@ -23,6 +23,7 @@
- #include <linux/bitmap.h>
- #include <net/cfg80211.h>
-+#include "ieee80211_common.h"
- #include "ieee80211_i.h"
- #include "ieee80211_rate.h"
- #include "wep.h"
-@@ -121,6 +122,152 @@
-       ieee80211_configure_filter(local);
- }
-+/* management interface */
-+
-+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;
-+              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 net_device *dev = local->apdev;
-+
-+      skb->dev = dev;
-+
-+      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);
-+
-+      dev->stats.rx_packets++;
-+      dev->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 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;
-+}
-+
-+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;
-+}
-+
-+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->open = ieee80211_mgmt_open;
-+      dev->stop = ieee80211_mgmt_stop;
-+      dev->type = ARPHRD_IEEE80211_PRISM;
-+      dev->hard_header_parse = &header_parse_80211;
-+      dev->destructor = ieee80211_if_free;
-+}
-+
- /* regular interfaces */
- static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
-@@ -198,6 +345,7 @@
-                       return -ENOLINK;
-               break;
-       case IEEE80211_IF_TYPE_AP:
-+      case IEEE80211_IF_TYPE_MGMT:
-       case IEEE80211_IF_TYPE_STA:
-       case IEEE80211_IF_TYPE_MNTR:
-       case IEEE80211_IF_TYPE_IBSS:
-@@ -262,6 +410,10 @@
-       if (local->open_count == 0) {
-               res = dev_open(local->mdev);
-               WARN_ON(res);
-+              if (local->apdev) {
-+                      res = dev_open(local->apdev);
-+                      WARN_ON(res);
-+              }
-               tasklet_enable(&local->tx_pending_tasklet);
-               tasklet_enable(&local->tasklet);
-       }
-@@ -347,6 +499,9 @@
-               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));
-@@ -646,6 +801,8 @@
-               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
-       if (control->flags & IEEE80211_TXCTL_REQUEUE)
-               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
-+      if (control->type == IEEE80211_IF_TYPE_MGMT)
-+              pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
-       pkt_data->queue = control->queue;
-       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-@@ -698,6 +855,7 @@
-       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;
-@@ -812,9 +970,29 @@
-                       local->dot11FailedCount++;
-       }
-+      msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
-+              ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
-+
-       /* this was a transmitted frame, but now we want to reuse it */
-       skb_orphan(skb);
-+      if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
-+          local->apdev) {
-+              if (local->monitors) {
-+                      skb2 = skb_clone(skb, GFP_ATOMIC);
-+              } else {
-+                      skb2 = skb;
-+                      skb = NULL;
-+              }
-+
-+              if (skb2)
-+                      /* Send frame to hostapd */
-+                      ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
-+
-+              if (!skb)
-+                      return;
-+      }
-+
-       if (!local->monitors) {
-               dev_kfree_skb(skb);
-               return;
-@@ -1161,6 +1339,8 @@
-       BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-       local->reg_state = IEEE80211_DEV_UNREGISTERED;
-+      if (local->apdev)
-+              ieee80211_if_del_mgmt(local);
-       /*
-        * At this point, interface list manipulations are fine
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h   2007-11-11 15:15:42.840035769 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h        2007-11-11 15:15:53.792659922 +0100
-@@ -142,6 +142,7 @@
-                        * 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) */
-@@ -163,6 +164,7 @@
- #define IEEE80211_TXPD_REQ_TX_STATUS  BIT(0)
- #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
- #define IEEE80211_TXPD_REQUEUE                BIT(2)
-+#define IEEE80211_TXPD_MGMT_IFACE     BIT(3)
- /* Stored in sk_buff->cb */
- struct ieee80211_tx_packet_data {
-       int ifindex;
-@@ -408,6 +410,7 @@
-       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_* */
-@@ -701,11 +704,14 @@
- 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);
-+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);
- struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
-                                         int phymode, int hwrate);
-@@ -772,6 +778,8 @@
- 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);
-@@ -788,6 +796,7 @@
- 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);
-+int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
- /* utility functions/constants */
- extern void *mac80211_wiphy_privid; /* for wiphy privid */
-Index: mac80211/net/mac80211/ieee80211_iface.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_iface.c       2007-11-11 15:15:42.848036222 +0100
-+++ mac80211/net/mac80211/ieee80211_iface.c    2007-11-11 15:15:53.796660158 +0100
-@@ -96,6 +96,66 @@
-       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;
-+
-+      /*
-+       * Called even when register_netdevice fails, it would
-+       * oops if assigned before initialising the rest.
-+       */
-+      ndev->uninit = ieee80211_if_reinit;
-+
-+      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);
-@@ -183,6 +243,9 @@
-       ieee80211_if_sdata_deinit(sdata);
-       switch (sdata->type) {
-+      case IEEE80211_IF_TYPE_MGMT:
-+              /* nothing to do */
-+              break;
-       case IEEE80211_IF_TYPE_INVALID:
-               /* cannot happen */
-               WARN_ON(1);
-@@ -294,8 +357,11 @@
- 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: mac80211/net/mac80211/ieee80211_rate.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.c        2007-11-11 15:15:42.852036451 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.c     2007-11-11 15:15:53.800660386 +0100
-@@ -145,7 +145,8 @@
-       struct rate_control_ref *ref, *old;
-       ASSERT_RTNL();
--      if (local->open_count || netif_running(local->mdev))
-+      if (local->open_count || netif_running(local->mdev) ||
-+          (local->apdev && netif_running(local->apdev)))
-               return -EBUSY;
-       ref = rate_control_alloc(name, local);
-Index: mac80211/net/mac80211/ieee80211_rate.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.h        2007-11-11 15:15:42.860036908 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.h     2007-11-11 15:15:53.800660386 +0100
-@@ -30,6 +30,8 @@
-       /* 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;
- };
-Index: mac80211/net/mac80211/ieee80211_sta.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:42.868037362 +0100
-+++ mac80211/net/mac80211/ieee80211_sta.c      2007-11-11 15:15:53.800660386 +0100
-@@ -475,6 +475,8 @@
-       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;
-+      if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+              pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
-       if (!encrypt)
-               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
-Index: mac80211/net/mac80211/rx.c
-===================================================================
---- mac80211.orig/net/mac80211/rx.c    2007-11-11 15:15:42.872037591 +0100
-+++ mac80211/net/mac80211/rx.c 2007-11-11 15:15:53.804660611 +0100
-@@ -19,6 +19,7 @@
- #include "ieee80211_i.h"
- #include "ieee80211_led.h"
-+#include "ieee80211_common.h"
- #include "wep.h"
- #include "wpa.h"
- #include "tkip.h"
-@@ -411,7 +412,12 @@
-                       return TXRX_DROP;
-               }
--              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;
-       }
-       return TXRX_CONTINUE;
-@@ -953,8 +959,15 @@
- {
-       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;
-+          (rx->flags & IEEE80211_TXRXD_RXRA_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 &&
-@@ -1196,8 +1209,13 @@
-            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;
-+      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;
- }
-@@ -1407,6 +1425,7 @@
-               /* take everything */
-               break;
-       case IEEE80211_IF_TYPE_INVALID:
-+      case IEEE80211_IF_TYPE_MGMT:
-               /* should never get here */
-               WARN_ON(1);
-               break;
-Index: mac80211/net/mac80211/tx.c
-===================================================================
---- mac80211.orig/net/mac80211/tx.c    2007-11-11 15:15:42.880038048 +0100
-+++ mac80211/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100
-@@ -258,7 +258,7 @@
-               return TXRX_CONTINUE;
-       }
--      if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
-+      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
-@@ -568,6 +568,8 @@
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = tx->u.tx.mode;
-               extra.ethertype = tx->ethertype;
-+              extra.mgmt_data = tx->sdata &&
-+                                tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
-               tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
-                                                     tx->skb, &extra);
-@@ -1076,7 +1078,7 @@
- }
- static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
--                      struct ieee80211_tx_control *control)
-+                      struct ieee80211_tx_control *control, int mgmt)
- {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-@@ -1107,6 +1109,7 @@
-       rcu_read_lock();
-       sta = tx.sta;
-+      tx.u.tx.mgmt_interface = mgmt;
-       tx.u.tx.mode = local->hw.conf.mode;
-       for (handler = local->tx_handlers; *handler != NULL;
-@@ -1253,7 +1256,8 @@
-               control.flags |= IEEE80211_TXCTL_REQUEUE;
-       control.queue = pkt_data->queue;
--      ret = ieee80211_tx(odev, skb, &control);
-+      ret = ieee80211_tx(odev, skb, &control,
-+                         control.type == IEEE80211_IF_TYPE_MGMT);
-       dev_put(odev);
-       return ret;
-@@ -1498,6 +1502,8 @@
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-       pkt_data->ifindex = dev->ifindex;
-+      if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+              pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
-       skb->dev = local->mdev;
-       dev->stats.tx_packets++;
-@@ -1555,6 +1561,8 @@
-       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;
-+      if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+              pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
-       skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
-       skb->dev = sdata->local->mdev;
-Index: mac80211/net/mac80211/wme.c
-===================================================================
---- mac80211.orig/net/mac80211/wme.c   2007-11-11 15:15:42.888038502 +0100
-+++ mac80211/net/mac80211/wme.c        2007-11-11 15:15:53.804660611 +0100
-@@ -94,6 +94,8 @@
- static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
- {
-       struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
-+      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;
-@@ -106,8 +108,12 @@
-               return IEEE80211_TX_QUEUE_DATA0;
-       }
--      if (0 /* injected */) {
--              /* use AC from radiotap */
-+      if (unlikely(pkt_data->flags & IEEE80211_TXPD_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];
-       }
-       /* is this a QoS frame? */
-Index: mac80211/net/mac80211/ieee80211_ioctl.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_ioctl.c       2007-11-11 15:15:51.532531127 +0100
-+++ mac80211/net/mac80211/ieee80211_ioctl.c    2007-11-11 15:15:53.808660833 +0100
-@@ -840,16 +840,29 @@
-                                       void *wrqu, char *extra)
- {
-       struct ieee80211_sub_if_data *sdata;
-+      struct ieee80211_local *local;
-       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);
-+      local = sdata->local;
-       switch (param) {
-+      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;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-@@ -864,12 +877,20 @@
-                                           void *wrqu, char *extra)
- {
-       struct ieee80211_sub_if_data *sdata;
-+      struct ieee80211_local *local;
-       int *param = (int *) extra;
-       int ret = 0;
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      local = sdata->local;
-       switch (*param) {
-+      case PRISM2_PARAM_MGMT_IF:
-+              if (local->apdev)
-+                      *param = local->apdev->ifindex;
-+              else
-+                      ret = -ENOENT;
-+              break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
diff --git a/package/mac80211/patches/011-allow-ap-vlan-modes.patch b/package/mac80211/patches/011-allow-ap-vlan-modes.patch
deleted file mode 100644 (file)
index d0edfe8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-Subject: mac80211: allow AP and VLAN modes
-
-This adds AP/VLAN modes to the list of modes that a mac80211
-interface can be created in/switched into.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c             |    4 ++++
- net/mac80211/ieee80211_ioctl.c |    3 +++
- 2 files changed, 7 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c 2007-10-30 15:33:43.227379286 +0100
-+++ everything/net/mac80211/cfg.c      2007-11-07 13:19:27.981515569 +0100
-@@ -25,6 +25,10 @@ nl80211_type_to_mac80211_type(enum nl802
-               return IEEE80211_IF_TYPE_STA;
-       case NL80211_IFTYPE_MONITOR:
-               return IEEE80211_IF_TYPE_MNTR;
-+      case NL80211_IFTYPE_AP:
-+              return IEEE80211_IF_TYPE_AP;
-+      case NL80211_IFTYPE_AP_VLAN:
-+              return IEEE80211_IF_TYPE_VLAN;
-       default:
-               return IEEE80211_IF_TYPE_INVALID;
-       }
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:19:25.851524684 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:27.981515569 +0100
-@@ -284,6 +284,9 @@ static int ieee80211_ioctl_siwmode(struc
-       case IW_MODE_MONITOR:
-               type = IEEE80211_IF_TYPE_MNTR;
-               break;
-+      case IW_MODE_MASTER:
-+              type = IEEE80211_IF_TYPE_AP;
-+              break;
-       default:
-               return -EINVAL;
-       }
diff --git a/package/mac80211/patches/012-mac80211-allow-wds.patch b/package/mac80211/patches/012-mac80211-allow-wds.patch
deleted file mode 100644 (file)
index d5c57cd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Subject: mac80211: allow WDS mode
-
-This allows creating interfaces in WDS mode or switching
-existing ones into WDS mode (both via cfg80211.)
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |    2 ++
- 1 file changed, 2 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:27.981515569 +0100
-+++ everything/net/mac80211/cfg.c      2007-11-07 13:19:29.441515732 +0100
-@@ -29,6 +29,8 @@ nl80211_type_to_mac80211_type(enum nl802
-               return IEEE80211_IF_TYPE_AP;
-       case NL80211_IFTYPE_AP_VLAN:
-               return IEEE80211_IF_TYPE_VLAN;
-+      case NL80211_IFTYPE_WDS:
-+              return IEEE80211_IF_TYPE_WDS;
-       default:
-               return IEEE80211_IF_TYPE_INVALID;
-       }
diff --git a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch b/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch
deleted file mode 100644 (file)
index d418ad3..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:19:27.981515569 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:30.781513182 +0100
-@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
-       local = sdata->local;
-       switch (param) {
-+      case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-+              local->bridge_packets = value;
-+              break;
-       case PRISM2_PARAM_MGMT_IF:
-               if (value == 1) {
-                       if (!local->apdev)
-@@ -914,6 +917,9 @@ static int ieee80211_ioctl_get_prism2_pa
-       local = sdata->local;
-       switch (*param) {
-+      case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-+              *param = local->bridge_packets;
-+              break;
-       case PRISM2_PARAM_MGMT_IF:
-               if (local->apdev)
-                       *param = local->apdev->ifindex;
diff --git a/package/mac80211/patches/014-prism2-ioctl-8021x.patch b/package/mac80211/patches/014-prism2-ioctl-8021x.patch
deleted file mode 100644 (file)
index 5feb01e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:19:30.781513182 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:32.281514919 +0100
-@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
-       local = sdata->local;
-       switch (param) {
-+      case PRISM2_PARAM_IEEE_802_1X:
-+              sdata->ieee802_1x = value;
-+              break;
-       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-               local->bridge_packets = value;
-               break;
-@@ -917,6 +920,9 @@ static int ieee80211_ioctl_get_prism2_pa
-       local = sdata->local;
-       switch (*param) {
-+      case PRISM2_PARAM_IEEE_802_1X:
-+              *param = sdata->ieee802_1x;
-+              break;
-       case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-               *param = local->bridge_packets;
-               break;
diff --git a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch b/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch
deleted file mode 100644 (file)
index d6e5dfd..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |  102 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 102 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:19:32.281514919 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:33.681513453 +0100
-@@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru
-       return -EOPNOTSUPP;
- }
-+/*
-+ * Wow. This ioctl interface is such crap, it's tied
-+ * to internal definitions. I hope it dies soon.
-+ */
-+static int mode_to_hostapd_mode(enum ieee80211_phymode mode)
-+{
-+      switch (mode) {
-+      case MODE_IEEE80211A:
-+              return 0;
-+      case MODE_IEEE80211B:
-+              return 1;
-+      case MODE_IEEE80211G:
-+              return 3;
-+      case NUM_IEEE80211_MODES:
-+              WARN_ON(1);
-+              break;
-+      }
-+      WARN_ON(1);
-+      return -1;
-+}
-+
-+static int channel_flags_to_hostapd_flags(int flags)
-+{
-+      int res = 0;
-+
-+      if (flags & IEEE80211_CHAN_W_SCAN)
-+              res |= 1;
-+      if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN)
-+              res |= 2;
-+      if (flags & IEEE80211_CHAN_W_IBSS)
-+              res |= 4;
-+
-+      return res;
-+}
-+
-+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 */
-+};
-+
-+static int ieee80211_ioctl_get_hw_features(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.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;
-+
-+      param->u.hw_features.flags = 0;
-+
-+      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_to_hostapd_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 = channel_flags_to_hostapd_flags(
-+                                              mode->channels[i].flag);
-+              }
-+              pos += clen;
-+
-+              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;
-+      }
-+
-+      return 0;
-+}
-+
- static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
-                                       struct iw_point *p)
-@@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd(
-       }
-       switch (param->cmd) {
-+      case PRISM2_HOSTAPD_GET_HW_FEATURES:
-+              ret = ieee80211_ioctl_get_hw_features(dev, param, p->length);
-+              break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
diff --git a/package/mac80211/patches/016-prism2-ioctl-eapol.patch b/package/mac80211/patches/016-prism2-ioctl-eapol.patch
deleted file mode 100644 (file)
index 5ce5758..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c     2007-11-07 13:19:33.681513453 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c  2007-11-07 13:19:35.171517576 +0100
-@@ -984,6 +984,9 @@ static int ieee80211_ioctl_prism2_param(
-       local = sdata->local;
-       switch (param) {
-+      case PRISM2_PARAM_EAPOL:
-+              sdata->eapol = value;
-+              break;
-       case PRISM2_PARAM_IEEE_802_1X:
-               sdata->ieee802_1x = value;
-               break;
-@@ -1022,6 +1025,9 @@ static int ieee80211_ioctl_get_prism2_pa
-       local = sdata->local;
-       switch (*param) {
-+      case PRISM2_PARAM_EAPOL:
-+              *param = sdata->eapol;
-+              break;
-       case PRISM2_PARAM_IEEE_802_1X:
-               *param = sdata->ieee802_1x;
-               break;
diff --git a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch b/package/mac80211/patches/017-nl80211-add-key-mgmt.patch
deleted file mode 100644 (file)
index f5b1d45..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-Subject: cfg80211/nl80211: introduce key handling
-
-This introduces key handling to cfg80211/nl80211. Default
-and group keys can be added, changed and removed; sequence
-counters for each key can be retrieved.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   34 +++++
- include/net/cfg80211.h  |   44 +++++++
- net/wireless/core.c     |    3 
- net/wireless/nl80211.c  |  289 ++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 370 insertions(+)
-
---- everything.orig/include/linux/nl80211.h    2007-10-30 15:33:43.587381346 +0100
-+++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100
-@@ -37,6 +37,16 @@
-  *    userspace to request deletion of a virtual interface, then requires
-  *    attribute %NL80211_ATTR_IFINDEX.
-  *
-+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
-+ *    by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
-+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
-+ *    %NL80211_ATTR_KEY_THRESHOLD.
-+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
-+ *    %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
-+ *    attributes.
-+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
-+ *    or %NL80211_ATTR_MAC.
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -54,6 +64,11 @@ enum nl80211_commands {
-       NL80211_CMD_NEW_INTERFACE,
-       NL80211_CMD_DEL_INTERFACE,
-+      NL80211_CMD_GET_KEY,
-+      NL80211_CMD_SET_KEY,
-+      NL80211_CMD_NEW_KEY,
-+      NL80211_CMD_DEL_KEY,
-+
-       /* add commands here */
-       /* used to define NL80211_CMD_MAX below */
-@@ -75,6 +90,17 @@ enum nl80211_commands {
-  * @NL80211_ATTR_IFNAME: network interface name
-  * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
-  *
-+ * @NL80211_ATTR_MAC: MAC address (various uses)
-+ *
-+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
-+ *    16 bytes encryption key followed by 8 bytes each for TX and RX MIC
-+ *    keys
-+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
-+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
-+ *    section 7.3.2.25.1, e.g. 0x000FAC04)
-+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
-+ *    CCMP keys, each six bytes in little endian
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -89,6 +115,14 @@ enum nl80211_attrs {
-       NL80211_ATTR_IFNAME,
-       NL80211_ATTR_IFTYPE,
-+      NL80211_ATTR_MAC,
-+
-+      NL80211_ATTR_KEY_DATA,
-+      NL80211_ATTR_KEY_IDX,
-+      NL80211_ATTR_KEY_CIPHER,
-+      NL80211_ATTR_KEY_SEQ,
-+      NL80211_ATTR_KEY_DEFAULT,
-+
-       /* add attributes here, update the policy in nl80211.c */
-       __NL80211_ATTR_AFTER_LAST,
---- everything.orig/net/wireless/nl80211.c     2007-10-30 15:33:43.637380153 +0100
-+++ everything/net/wireless/nl80211.c  2007-11-07 13:19:38.201511066 +0100
-@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
-       [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
-       [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
-       [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
-+
-+      [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
-+
-+      [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
-+                                  .len = WLAN_MAX_KEY_LEN },
-+      [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
-+      [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
-+      [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
- };
- /* message building helper */
-@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct 
-       return err;
- }
-+struct get_key_cookie {
-+      struct sk_buff *msg;
-+      int error;
-+};
-+
-+static void get_key_callback(void *c, struct key_params *params)
-+{
-+      struct get_key_cookie *cookie = c;
-+
-+      if (params->key)
-+              NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
-+                      params->key_len, params->key);
-+
-+      if (params->seq)
-+              NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
-+                      params->seq_len, params->seq);
-+
-+      if (params->cipher)
-+              NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
-+                          params->cipher);
-+
-+      return;
-+ nla_put_failure:
-+      cookie->error = 1;
-+}
-+
-+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      u8 key_idx = 0;
-+      u8 *mac_addr = NULL;
-+      struct get_key_cookie cookie = {
-+              .error = 0,
-+      };
-+      void *hdr;
-+      struct sk_buff *msg;
-+
-+      if (info->attrs[NL80211_ATTR_KEY_IDX])
-+              key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+      if (key_idx > 3)
-+              return -EINVAL;
-+
-+      if (info->attrs[NL80211_ATTR_MAC])
-+              mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->get_key) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+      if (!msg) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
-+
-+      hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-+                           NL80211_CMD_NEW_KEY);
-+
-+      if (IS_ERR(hdr)) {
-+              err = PTR_ERR(hdr);
-+              goto out;
-+      }
-+
-+      cookie.msg = msg;
-+
-+      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-+      NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-+      if (mac_addr)
-+              NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
-+
-+      rtnl_lock();
-+      err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
-+                              &cookie, get_key_callback);
-+      rtnl_unlock();
-+
-+      if (err)
-+              goto out;
-+
-+      if (cookie.error)
-+              goto nla_put_failure;
-+
-+      genlmsg_end(msg, hdr);
-+      err = genlmsg_unicast(msg, info->snd_pid);
-+      goto out;
-+
-+ nla_put_failure:
-+      err = -ENOBUFS;
-+      nlmsg_free(msg);
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      u8 key_idx;
-+
-+      if (!info->attrs[NL80211_ATTR_KEY_IDX])
-+              return -EINVAL;
-+
-+      key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+      if (key_idx > 3)
-+              return -EINVAL;
-+
-+      /* currently only support setting default key */
-+      if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
-+              return -EINVAL;
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->set_default_key) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      struct key_params params;
-+      u8 key_idx = 0;
-+      u8 *mac_addr = NULL;
-+
-+      memset(&params, 0, sizeof(params));
-+
-+      if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
-+              return -EINVAL;
-+
-+      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_IDX])
-+              key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+      params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-+
-+      if (info->attrs[NL80211_ATTR_MAC])
-+              mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      if (key_idx > 3)
-+              return -EINVAL;
-+
-+      /*
-+       * Disallow pairwise keys with non-zero index unless it's WEP
-+       * (because current deployments use pairwise WEP keys with
-+       * non-zero indizes but 802.11i clearly specifies to use zero)
-+       */
-+      if (mac_addr && key_idx &&
-+          params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
-+          params.cipher != WLAN_CIPHER_SUITE_WEP104)
-+              return -EINVAL;
-+
-+      /* TODO: add definitions for the lengths to linux/ieee80211.h */
-+      switch (params.cipher) {
-+      case WLAN_CIPHER_SUITE_WEP40:
-+              if (params.key_len != 5)
-+                      return -EINVAL;
-+              break;
-+      case WLAN_CIPHER_SUITE_TKIP:
-+              if (params.key_len != 32)
-+                      return -EINVAL;
-+              break;
-+      case WLAN_CIPHER_SUITE_CCMP:
-+              if (params.key_len != 16)
-+                      return -EINVAL;
-+              break;
-+      case WLAN_CIPHER_SUITE_WEP104:
-+              if (params.key_len != 13)
-+                      return -EINVAL;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->add_key) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      u8 key_idx = 0;
-+      u8 *mac_addr = NULL;
-+
-+      if (info->attrs[NL80211_ATTR_KEY_IDX])
-+              key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+      if (key_idx > 3)
-+              return -EINVAL;
-+
-+      if (info->attrs[NL80211_ATTR_MAC])
-+              mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->del_key) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
-       {
-               .cmd = NL80211_CMD_GET_WIPHY,
-@@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-+      {
-+              .cmd = NL80211_CMD_GET_KEY,
-+              .doit = nl80211_get_key,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_SET_KEY,
-+              .doit = nl80211_set_key,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_NEW_KEY,
-+              .doit = nl80211_new_key,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_DEL_KEY,
-+              .doit = nl80211_del_key,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
- };
- /* multicast groups */
---- everything.orig/net/wireless/core.c        2007-10-30 15:33:43.677380478 +0100
-+++ everything/net/wireless/core.c     2007-11-07 13:19:38.221513833 +0100
-@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
-       struct cfg80211_registered_device *drv;
-       int alloc_size;
-+      WARN_ON(!ops->add_key && ops->del_key);
-+      WARN_ON(ops->add_key && !ops->del_key);
-+
-       alloc_size = sizeof(*drv) + sizeof_priv;
-       drv = kzalloc(alloc_size, GFP_KERNEL);
---- everything.orig/include/net/cfg80211.h     2007-10-30 15:33:43.617381780 +0100
-+++ everything/include/net/cfg80211.h  2007-11-07 13:19:38.231512748 +0100
-@@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
-    struct ieee80211_radiotap_iterator *iterator);
-+ /**
-+ * struct key_params - key information
-+ *
-+ * Information about a key
-+ *
-+ * @key: key material
-+ * @key_len: length of key material
-+ * @cipher: cipher suite selector
-+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
-+ *    with the get_key() callback, must be in little endian,
-+ *    length given by @seq_len.
-+ */
-+struct key_params {
-+      u8 *key;
-+      u8 *seq;
-+      int key_len;
-+      int seq_len;
-+      u32 cipher;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
-@@ -71,6 +91,18 @@ struct wiphy;
-  *
-  * @change_virtual_intf: change type of virtual interface
-  *
-+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
-+ *    when adding a group key.
-+ *
-+ * @get_key: get information about the key with the given parameters.
-+ *    @mac_addr will be %NULL when requesting information for a group
-+ *    key. All pointers given to the @callback function need not be valid
-+ *    after it returns.
-+ *
-+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
-+ *    and @key_index
-+ *
-+ * @set_default_key: set the default key on an interface
-  */
- struct cfg80211_ops {
-       int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -78,6 +110,18 @@ struct cfg80211_ops {
-       int     (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
-       int     (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
-                                      enum nl80211_iftype type);
-+
-+      int     (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
-+                         u8 key_index, u8 *mac_addr,
-+                         struct key_params *params);
-+      int     (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
-+                         u8 key_index, u8 *mac_addr, void *cookie,
-+                         void (*callback)(void *cookie, struct key_params*));
-+      int     (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
-+                         u8 key_index, u8 *mac_addr);
-+      int     (*set_default_key)(struct wiphy *wiphy,
-+                                 struct net_device *netdev,
-+                                 u8 key_index);
- };
- #endif /* __NET_CFG80211_H */
diff --git a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch b/package/mac80211/patches/018-mac80211-cfg80211-keys.patch
deleted file mode 100644 (file)
index 0c98623..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-Subject: mac80211: support adding/removing keys via cfg80211
-
-This adds the necessary hooks to mac80211 to allow userspace
-to edit keys with cfg80211 (through nl80211.)
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 91 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:29.441515732 +0100
-+++ everything/net/mac80211/cfg.c      2007-11-07 13:19:39.531517685 +0100
-@@ -6,6 +6,7 @@
-  * This file is GPLv2 as found in COPYING.
-  */
-+#include <linux/ieee80211.h>
- #include <linux/nl80211.h>
- #include <linux/rtnetlink.h>
- #include <net/net_namespace.h>
-@@ -105,8 +106,98 @@ static int ieee80211_change_iface(struct
-       return 0;
- }
-+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-+                           u8 key_idx, u8 *mac_addr,
-+                           struct key_params *params)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+      struct sta_info *sta = NULL;
-+      enum ieee80211_key_alg alg;
-+      int ret;
-+
-+      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      switch (params->cipher) {
-+      case WLAN_CIPHER_SUITE_WEP40:
-+      case WLAN_CIPHER_SUITE_WEP104:
-+              alg = ALG_WEP;
-+              break;
-+      case WLAN_CIPHER_SUITE_TKIP:
-+              alg = ALG_TKIP;
-+              break;
-+      case WLAN_CIPHER_SUITE_CCMP:
-+              alg = ALG_CCMP;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      if (mac_addr) {
-+              sta = sta_info_get(sdata->local, mac_addr);
-+              if (!sta)
-+                      return -ENOENT;
-+      }
-+
-+      ret = 0;
-+      if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
-+                               params->key_len, params->key))
-+              ret = -ENOMEM;
-+
-+      if (sta)
-+              sta_info_put(sta);
-+
-+      return ret;
-+}
-+
-+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-+                           u8 key_idx, u8 *mac_addr)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+      struct sta_info *sta;
-+      int ret;
-+
-+      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      if (mac_addr) {
-+              sta = sta_info_get(sdata->local, mac_addr);
-+              if (!sta)
-+                      return -ENOENT;
-+
-+              ret = 0;
-+              if (sta->key)
-+                      ieee80211_key_free(sta->key);
-+              else
-+                      ret = -ENOENT;
-+
-+              sta_info_put(sta);
-+              return ret;
-+      }
-+
-+      if (!sdata->keys[key_idx])
-+              return -ENOENT;
-+
-+      ieee80211_key_free(sdata->keys[key_idx]);
-+
-+      return 0;
-+}
-+
-+static int ieee80211_config_default_key(struct wiphy *wiphy,
-+                                      struct net_device *dev,
-+                                      u8 key_idx)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+
-+      sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      ieee80211_set_default_key(sdata, key_idx);
-+
-+      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,
-+      .add_key = ieee80211_add_key,
-+      .del_key = ieee80211_del_key,
-+      .set_default_key = ieee80211_config_default_key,
- };
diff --git a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch b/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch
deleted file mode 100644 (file)
index 5d0020b..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-Subject: mac80211: support getting key sequence counters via cfg80211
-
-This implements cfg80211's get_key() to allow retrieving the sequence
-counter for a TKIP or CCMP key from userspace. It also cleans up and
-documents the associated low-level driver interface.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/net/mac80211.h |   14 ++------
- net/mac80211/cfg.c     |   85 ++++++++++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 89 insertions(+), 10 deletions(-)
-
-Index: mac80211/net/mac80211/cfg.c
-===================================================================
---- mac80211.orig/net/mac80211/cfg.c   2007-11-11 15:46:41.497954646 +0100
-+++ mac80211/net/mac80211/cfg.c        2007-11-11 15:46:51.346515884 +0100
-@@ -1,7 +1,7 @@
- /*
-  * mac80211 configuration hooks for cfg80211
-  *
-- * Copyright 2006     Johannes Berg <johannes@sipsolutions.net>
-+ * Copyright 2006, 2007       Johannes Berg <johannes@sipsolutions.net>
-  *
-  * This file is GPLv2 as found in COPYING.
-  */
-@@ -180,6 +180,88 @@
-       return 0;
- }
-+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-+                           u8 key_idx, u8 *mac_addr, void *cookie,
-+                           void (*callback)(void *cookie,
-+                                            struct key_params *params))
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct sta_info *sta = NULL;
-+      u8 seq[6] = {0};
-+      struct key_params params;
-+      struct ieee80211_key *key;
-+      u32 iv32;
-+      u16 iv16;
-+      int err = -ENOENT;
-+
-+      if (mac_addr) {
-+              sta = sta_info_get(sdata->local, mac_addr);
-+              if (!sta)
-+                      goto out;
-+
-+              key = sta->key;
-+      } else
-+              key = sdata->keys[key_idx];
-+
-+      if (!key)
-+              goto out;
-+
-+      memset(&params, 0, sizeof(params));
-+
-+      switch (key->conf.alg) {
-+      case ALG_TKIP:
-+              params.cipher = WLAN_CIPHER_SUITE_TKIP;
-+
-+              iv32 = key->u.tkip.iv32;
-+              iv16 = key->u.tkip.iv16;
-+
-+              if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
-+                  sdata->local->ops->get_tkip_seq)
-+                      sdata->local->ops->get_tkip_seq(
-+                              local_to_hw(sdata->local),
-+                              key->conf.hw_key_idx,
-+                              &iv32, &iv16);
-+
-+              seq[0] = iv16 & 0xff;
-+              seq[1] = (iv16 >> 8) & 0xff;
-+              seq[2] = iv32 & 0xff;
-+              seq[3] = (iv32 >> 8) & 0xff;
-+              seq[4] = (iv32 >> 16) & 0xff;
-+              seq[5] = (iv32 >> 24) & 0xff;
-+              params.seq = seq;
-+              params.seq_len = 6;
-+              break;
-+      case ALG_CCMP:
-+              params.cipher = WLAN_CIPHER_SUITE_CCMP;
-+              seq[0] = key->u.ccmp.tx_pn[5];
-+              seq[1] = key->u.ccmp.tx_pn[4];
-+              seq[2] = key->u.ccmp.tx_pn[3];
-+              seq[3] = key->u.ccmp.tx_pn[2];
-+              seq[4] = key->u.ccmp.tx_pn[1];
-+              seq[5] = key->u.ccmp.tx_pn[0];
-+              params.seq = seq;
-+              params.seq_len = 6;
-+              break;
-+      case ALG_WEP:
-+              if (key->conf.keylen == 5)
-+                      params.cipher = WLAN_CIPHER_SUITE_WEP40;
-+              else
-+                      params.cipher = WLAN_CIPHER_SUITE_WEP104;
-+              break;
-+      }
-+
-+      params.key = key->conf.key;
-+      params.key_len = key->conf.keylen;
-+
-+      callback(cookie, &params);
-+      err = 0;
-+
-+ out:
-+      if (sta)
-+              sta_info_put(sta);
-+      return err;
-+}
-+
- static int ieee80211_config_default_key(struct wiphy *wiphy,
-                                       struct net_device *dev,
-                                       u8 key_idx)
-@@ -198,5 +280,6 @@
-       .change_virtual_intf = ieee80211_change_iface,
-       .add_key = ieee80211_add_key,
-       .del_key = ieee80211_del_key,
-+      .get_key = ieee80211_get_key,
-       .set_default_key = ieee80211_config_default_key,
- };
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h       2007-11-11 15:46:41.377947807 +0100
-+++ mac80211/include/net/mac80211.h    2007-11-11 15:47:08.183475366 +0100
-@@ -598,9 +598,6 @@
-       u8 key[0];
- };
--#define IEEE80211_SEQ_COUNTER_RX      0
--#define IEEE80211_SEQ_COUNTER_TX      1
--
- /**
-  * enum set_key_cmd - key command
-  *
-@@ -947,9 +944,9 @@
-  *
-  * @get_stats: return low-level statistics
-  *
-- * @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.
-+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
-+ *    callback should be provided to read the TKIP transmit IVs (both IV32
-+ *    and IV16) for the given key from hardware.
-  *
-  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
-  *
-@@ -1022,9 +1019,8 @@
-       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 (*get_sequence_counter)(struct ieee80211_hw *hw,
--                                  u8* addr, u8 keyidx, u8 txrx,
--                                  u32* iv32, u16* iv16);
-+      void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
-+                           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,
diff --git a/package/mac80211/patches/020-nl80211-beacon-parameters.patch b/package/mac80211/patches/020-nl80211-beacon-parameters.patch
deleted file mode 100644 (file)
index 51836f3..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-Subject: cfg80211/nl80211: add beacon settings
-
-This adds the necessary API to cfg80211/nl80211 to allow
-changing beaconing settings.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   24 ++++++++
- include/net/cfg80211.h  |   33 +++++++++++
- net/wireless/nl80211.c  |  133 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 190 insertions(+)
-
---- everything.orig/include/net/cfg80211.h     2007-11-08 11:50:57.412840007 +0100
-+++ everything/include/net/cfg80211.h  2007-11-08 16:50:38.421522842 +0100
-@@ -69,6 +69,26 @@ struct key_params {
-       u32 cipher;
- };
-+/**
-+ * struct beacon_parameters - beacon parameters
-+ *
-+ * Used to configure the beacon for an interface.
-+ *
-+ * @head: head portion of beacon (before TIM IE)
-+ *     or %NULL if not changed
-+ * @tail: tail portion of beacon (after TIM IE)
-+ *     or %NULL if not changed
-+ * @interval: beacon interval or zero if not changed
-+ * @dtim_period: DTIM period or zero if not changed
-+ * @head_len: length of @head
-+ * @tail_len: length of @tail
-+ */
-+struct beacon_parameters {
-+      u8 *head, *tail;
-+      int interval, dtim_period;
-+      int head_len, tail_len;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
-@@ -103,6 +123,13 @@ struct wiphy;
-  *    and @key_index
-  *
-  * @set_default_key: set the default key on an interface
-+ *
-+ * @add_beacon: Add a beacon with given parameters, @head, @interval
-+ *    and @dtim_period will be valid, @tail is optional.
-+ * @set_beacon: Change the beacon parameters for an access point mode
-+ *    interface. This should reject the call when no beacon has been
-+ *    configured.
-+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
-  */
- struct cfg80211_ops {
-       int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -122,6 +149,12 @@ struct cfg80211_ops {
-       int     (*set_default_key)(struct wiphy *wiphy,
-                                  struct net_device *netdev,
-                                  u8 key_index);
-+
-+      int     (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
-+                            struct beacon_parameters *info);
-+      int     (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
-+                            struct beacon_parameters *info);
-+      int     (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
- };
- #endif /* __NET_CFG80211_H */
---- everything.orig/include/linux/nl80211.h    2007-11-08 11:50:57.362839952 +0100
-+++ everything/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
-@@ -47,6 +47,15 @@
-  * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
-  *    or %NL80211_ATTR_MAC.
-  *
-+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
-+ *    %NL80222_CMD_NEW_BEACON message)
-+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
-+ *    using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
-+ *    %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
-+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
-+ *    parameters are like for %NL80211_CMD_SET_BEACON.
-+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -69,6 +78,11 @@ enum nl80211_commands {
-       NL80211_CMD_NEW_KEY,
-       NL80211_CMD_DEL_KEY,
-+      NL80211_CMD_GET_BEACON,
-+      NL80211_CMD_SET_BEACON,
-+      NL80211_CMD_NEW_BEACON,
-+      NL80211_CMD_DEL_BEACON,
-+
-       /* add commands here */
-       /* used to define NL80211_CMD_MAX below */
-@@ -101,6 +115,11 @@ enum nl80211_commands {
-  * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
-  *    CCMP keys, each six bytes in little endian
-  *
-+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
-+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
-+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
-+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -123,6 +142,11 @@ enum nl80211_attrs {
-       NL80211_ATTR_KEY_SEQ,
-       NL80211_ATTR_KEY_DEFAULT,
-+      NL80211_ATTR_BEACON_INTERVAL,
-+      NL80211_ATTR_DTIM_PERIOD,
-+      NL80211_ATTR_BEACON_HEAD,
-+      NL80211_ATTR_BEACON_TAIL,
-+
-       /* add attributes here, update the policy in nl80211.c */
-       __NL80211_ATTR_AFTER_LAST,
---- everything.orig/net/wireless/nl80211.c     2007-11-08 11:50:57.382836589 +0100
-+++ everything/net/wireless/nl80211.c  2007-11-08 16:58:36.711524524 +0100
-@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[
-       [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
-       [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
-       [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-+
-+      [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
-+      [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
-+      [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
-+                                     .len = IEEE80211_MAX_DATA_LEN },
-+      [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
-+                                     .len = IEEE80211_MAX_DATA_LEN },
- };
- /* message building helper */
-@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf
-       return err;
- }
-+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
-+{
-+        int (*call)(struct wiphy *wiphy, struct net_device *dev,
-+                  struct beacon_parameters *info);
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      struct beacon_parameters params;
-+      int haveinfo = 0;
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      switch (info->genlhdr->cmd) {
-+      case NL80211_CMD_NEW_BEACON:
-+              /* these are required for NEW_BEACON */
-+              if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
-+                  !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-+                  !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-+                      err = -EINVAL;
-+                      goto out;
-+              }
-+
-+              call = drv->ops->add_beacon;
-+              break;
-+      case NL80211_CMD_SET_BEACON:
-+              call = drv->ops->set_beacon;
-+              break;
-+      default:
-+              WARN_ON(1);
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      if (!call) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      memset(&params, 0, sizeof(params));
-+
-+      if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
-+              params.interval =
-+                  nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
-+              haveinfo = 1;
-+      }
-+
-+      if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
-+              params.dtim_period =
-+                  nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-+              haveinfo = 1;
-+      }
-+
-+      if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-+              params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-+              params.head_len =
-+                  nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-+              haveinfo = 1;
-+      }
-+
-+      if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
-+              params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-+              params.tail_len =
-+                  nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-+              haveinfo = 1;
-+      }
-+
-+      if (!haveinfo) {
-+              err = -EINVAL;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = call(&drv->wiphy, dev, &params);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->del_beacon) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->del_beacon(&drv->wiphy, dev);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
-       {
-               .cmd = NL80211_CMD_GET_WIPHY,
-@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = {
-               .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-+      {
-+              .cmd = NL80211_CMD_SET_BEACON,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+              .doit = nl80211_addset_beacon,
-+      },
-+      {
-+              .cmd = NL80211_CMD_NEW_BEACON,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+              .doit = nl80211_addset_beacon,
-+      },
-+      {
-+              .cmd = NL80211_CMD_DEL_BEACON,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+              .doit = nl80211_del_beacon,
-+      },
- };
- /* multicast groups */
diff --git a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch b/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch
deleted file mode 100644 (file)
index 702c68f..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-Subject: mac80211: add beacon configuration via cfg80211
-
-This patch implements the cfg80211 hooks for configuring beaconing
-on an access point interface in mac80211. While doing so, it fixes
-a number of races that could badly crash the machine when the
-beacon is changed while being requested by the driver.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
-The dtim_count field should possibly also be part of the beacon
-structure, but the possible race there doesn't really matter,
-worst thing is that one beacon will be sent with a wrong dtim
-count if (and only if) userspace changes the dtim period during
-operation.
-
- net/mac80211/cfg.c             |  156 +++++++++++++++++++++++++++++++++++++++++
- net/mac80211/debugfs_netdev.c  |   27 -------
- net/mac80211/ieee80211_i.h     |   14 ++-
- net/mac80211/ieee80211_iface.c |    4 -
- net/mac80211/tx.c              |   63 ++++++++++------
- 5 files changed, 204 insertions(+), 60 deletions(-)
-
-Index: mac80211/net/mac80211/cfg.c
-===================================================================
---- mac80211.orig/net/mac80211/cfg.c   2007-11-11 15:17:12.837164411 +0100
-+++ mac80211/net/mac80211/cfg.c        2007-11-11 15:18:36.853952256 +0100
-@@ -9,6 +9,7 @@
- #include <linux/ieee80211.h>
- #include <linux/nl80211.h>
- #include <linux/rtnetlink.h>
-+#include <linux/rcupdate.h>
- #include <net/cfg80211.h>
- #include "ieee80211_i.h"
- #include "cfg.h"
-@@ -274,6 +275,158 @@
-       return 0;
- }
-+/*
-+ * This handles both adding a beacon and setting new beacon info
-+ */
-+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
-+                                 struct beacon_parameters *params)
-+{
-+      struct beacon_data *new, *old;
-+      int new_head_len, new_tail_len;
-+      int size;
-+      int err = -EINVAL;
-+
-+      old = sdata->u.ap.beacon;
-+
-+      /* head must not be zero-length */
-+      if (params->head && !params->head_len)
-+              return -EINVAL;
-+
-+      /*
-+       * This is a kludge. beacon interval should really be part
-+       * of the beacon information.
-+       */
-+      if (params->interval) {
-+              sdata->local->hw.conf.beacon_int = params->interval;
-+              if (ieee80211_hw_config(sdata->local))
-+                      return -EINVAL;
-+              /*
-+               * We updated some parameter so if below bails out
-+               * it's not an error.
-+               */
-+              err = 0;
-+      }
-+
-+      /* Need to have a beacon head if we don't have one yet */
-+      if (!params->head && !old)
-+              return err;
-+
-+      /* sorry, no way to start beaconing without dtim period */
-+      if (!params->dtim_period && !old)
-+              return err;
-+
-+      /* new or old head? */
-+      if (params->head)
-+              new_head_len = params->head_len;
-+      else
-+              new_head_len = old->head_len;
-+
-+      /* new or old tail? */
-+      if (params->tail || !old)
-+              /* params->tail_len will be zero for !params->tail */
-+              new_tail_len = params->tail_len;
-+      else
-+              new_tail_len = old->tail_len;
-+
-+      size = sizeof(*new) + new_head_len + new_tail_len;
-+
-+      new = kzalloc(size, GFP_KERNEL);
-+      if (!new)
-+              return -ENOMEM;
-+
-+      /* start filling the new info now */
-+
-+      /* new or old dtim period? */
-+      if (params->dtim_period)
-+              new->dtim_period = params->dtim_period;
-+      else
-+              new->dtim_period = old->dtim_period;
-+
-+      /*
-+       * pointers go into the block we allocated,
-+       * memory is | beacon_data | head | tail |
-+       */
-+      new->head = ((u8 *) new) + sizeof(*new);
-+      new->tail = new->head + new_head_len;
-+      new->head_len = new_head_len;
-+      new->tail_len = new_tail_len;
-+
-+      /* copy in head */
-+      if (params->head)
-+              memcpy(new->head, params->head, new_head_len);
-+      else
-+              memcpy(new->head, old->head, new_head_len);
-+
-+      /* copy in optional tail */
-+      if (params->tail)
-+              memcpy(new->tail, params->tail, new_tail_len);
-+      else
-+              if (old)
-+                      memcpy(new->tail, old->tail, new_tail_len);
-+
-+      rcu_assign_pointer(sdata->u.ap.beacon, new);
-+
-+      synchronize_rcu();
-+
-+      kfree(old);
-+
-+      return ieee80211_if_config_beacon(sdata->dev);
-+}
-+
-+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-+                              struct beacon_parameters *params)
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct beacon_data *old;
-+
-+      if (sdata->type != IEEE80211_IF_TYPE_AP)
-+              return -EINVAL;
-+
-+      old = sdata->u.ap.beacon;
-+
-+      if (old)
-+              return -EALREADY;
-+
-+      return ieee80211_config_beacon(sdata, params);
-+}
-+
-+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-+                              struct beacon_parameters *params)
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct beacon_data *old;
-+
-+      if (sdata->type != IEEE80211_IF_TYPE_AP)
-+              return -EINVAL;
-+
-+      old = sdata->u.ap.beacon;
-+
-+      if (!old)
-+              return -ENOENT;
-+
-+      return ieee80211_config_beacon(sdata, params);
-+}
-+
-+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct beacon_data *old;
-+
-+      if (sdata->type != IEEE80211_IF_TYPE_AP)
-+              return -EINVAL;
-+
-+      old = sdata->u.ap.beacon;
-+
-+      if (!old)
-+              return -ENOENT;
-+
-+      rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-+      synchronize_rcu();
-+      kfree(old);
-+
-+      return ieee80211_if_config_beacon(dev);
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
-       .add_virtual_intf = ieee80211_add_iface,
-       .del_virtual_intf = ieee80211_del_iface,
-@@ -282,4 +435,7 @@
-       .del_key = ieee80211_del_key,
-       .get_key = ieee80211_get_key,
-       .set_default_key = ieee80211_config_default_key,
-+      .add_beacon = ieee80211_add_beacon,
-+      .set_beacon = ieee80211_set_beacon,
-+      .del_beacon = ieee80211_del_beacon,
- };
-Index: mac80211/net/mac80211/debugfs_netdev.c
-===================================================================
---- mac80211.orig/net/mac80211/debugfs_netdev.c        2007-10-14 00:42:30.054156000 +0200
-+++ mac80211/net/mac80211/debugfs_netdev.c     2007-11-11 15:18:11.852527505 +0100
-@@ -124,7 +124,6 @@
- /* AP attributes */
- IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
--IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
- IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
- IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
- IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
-@@ -138,26 +137,6 @@
- }
- __IEEE80211_IF_FILE(num_buffered_multicast);
--static ssize_t ieee80211_if_fmt_beacon_head_len(
--      const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
--{
--      if (sdata->u.ap.beacon_head)
--              return scnprintf(buf, buflen, "%d\n",
--                               sdata->u.ap.beacon_head_len);
--      return scnprintf(buf, buflen, "\n");
--}
--__IEEE80211_IF_FILE(beacon_head_len);
--
--static ssize_t ieee80211_if_fmt_beacon_tail_len(
--      const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
--{
--      if (sdata->u.ap.beacon_tail)
--              return scnprintf(buf, buflen, "%d\n",
--                               sdata->u.ap.beacon_tail_len);
--      return scnprintf(buf, buflen, "\n");
--}
--__IEEE80211_IF_FILE(beacon_tail_len);
--
- /* WDS attributes */
- IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
-@@ -194,14 +173,11 @@
-       DEBUGFS_ADD(eapol, ap);
-       DEBUGFS_ADD(ieee8021_x, ap);
-       DEBUGFS_ADD(num_sta_ps, ap);
--      DEBUGFS_ADD(dtim_period, ap);
-       DEBUGFS_ADD(dtim_count, ap);
-       DEBUGFS_ADD(num_beacons, ap);
-       DEBUGFS_ADD(force_unicast_rateidx, ap);
-       DEBUGFS_ADD(max_ratectrl_rateidx, ap);
-       DEBUGFS_ADD(num_buffered_multicast, ap);
--      DEBUGFS_ADD(beacon_head_len, ap);
--      DEBUGFS_ADD(beacon_tail_len, ap);
- }
- static void add_wds_files(struct ieee80211_sub_if_data *sdata)
-@@ -287,14 +263,11 @@
-       DEBUGFS_DEL(eapol, ap);
-       DEBUGFS_DEL(ieee8021_x, ap);
-       DEBUGFS_DEL(num_sta_ps, ap);
--      DEBUGFS_DEL(dtim_period, ap);
-       DEBUGFS_DEL(dtim_count, ap);
-       DEBUGFS_DEL(num_beacons, ap);
-       DEBUGFS_DEL(force_unicast_rateidx, ap);
-       DEBUGFS_DEL(max_ratectrl_rateidx, ap);
-       DEBUGFS_DEL(num_buffered_multicast, ap);
--      DEBUGFS_DEL(beacon_head_len, ap);
--      DEBUGFS_DEL(beacon_tail_len, ap);
- }
- static void del_wds_files(struct ieee80211_sub_if_data *sdata)
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h   2007-11-11 15:15:53.792659922 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h        2007-11-11 15:18:11.864528190 +0100
-@@ -190,9 +190,14 @@
- typedef ieee80211_txrx_result (*ieee80211_rx_handler)
- (struct ieee80211_txrx_data *rx);
-+struct beacon_data {
-+      u8 *head, *tail;
-+      int head_len, tail_len;
-+      int dtim_period;
-+};
-+
- struct ieee80211_if_ap {
--      u8 *beacon_head, *beacon_tail;
--      int beacon_head_len, beacon_tail_len;
-+      struct beacon_data *beacon;
-       struct list_head vlans;
-@@ -205,7 +210,7 @@
-       u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
-       atomic_t num_sta_ps; /* number of stations in PS mode */
-       struct sk_buff_head ps_bc_buf;
--      int dtim_period, dtim_count;
-+      int dtim_count;
-       int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
-       int max_ratectrl_rateidx; /* max TX rateidx for rate control */
-       int num_beacons; /* number of TXed beacon frames for this BSS */
-@@ -361,14 +366,11 @@
-                       struct dentry *eapol;
-                       struct dentry *ieee8021_x;
-                       struct dentry *num_sta_ps;
--                      struct dentry *dtim_period;
-                       struct dentry *dtim_count;
-                       struct dentry *num_beacons;
-                       struct dentry *force_unicast_rateidx;
-                       struct dentry *max_ratectrl_rateidx;
-                       struct dentry *num_buffered_multicast;
--                      struct dentry *beacon_head_len;
--                      struct dentry *beacon_tail_len;
-               } ap;
-               struct {
-                       struct dentry *channel_use;
-Index: mac80211/net/mac80211/ieee80211_iface.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_iface.c       2007-11-11 15:15:53.796660158 +0100
-+++ mac80211/net/mac80211/ieee80211_iface.c    2007-11-11 15:18:11.868528415 +0100
-@@ -187,7 +187,6 @@
-               sdata->u.vlan.ap = NULL;
-               break;
-       case IEEE80211_IF_TYPE_AP:
--              sdata->u.ap.dtim_period = 2;
-               sdata->u.ap.force_unicast_rateidx = -1;
-               sdata->u.ap.max_ratectrl_rateidx = -1;
-               skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
-@@ -271,8 +270,7 @@
-                       }
-               }
--              kfree(sdata->u.ap.beacon_head);
--              kfree(sdata->u.ap.beacon_tail);
-+              kfree(sdata->u.ap.beacon);
-               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-                       local->total_ps_buffered--;
-Index: mac80211/net/mac80211/tx.c
-===================================================================
---- mac80211.orig/net/mac80211/tx.c    2007-11-11 15:15:53.804660611 +0100
-+++ mac80211/net/mac80211/tx.c 2007-11-11 15:18:11.868528415 +0100
-@@ -1656,7 +1656,8 @@
- static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
-                                    struct ieee80211_if_ap *bss,
--                                   struct sk_buff *skb)
-+                                   struct sk_buff *skb,
-+                                   struct beacon_data *beacon)
- {
-       u8 *pos, *tim;
-       int aid0 = 0;
-@@ -1672,7 +1673,7 @@
-                                         IEEE80211_MAX_AID+1);
-       if (bss->dtim_count == 0)
--              bss->dtim_count = bss->dtim_period - 1;
-+              bss->dtim_count = beacon->dtim_period - 1;
-       else
-               bss->dtim_count--;
-@@ -1680,7 +1681,7 @@
-       *pos++ = WLAN_EID_TIM;
-       *pos++ = 4;
-       *pos++ = bss->dtim_count;
--      *pos++ = bss->dtim_period;
-+      *pos++ = beacon->dtim_period;
-       if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
-               aid0 = 1;
-@@ -1728,8 +1729,9 @@
-       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;
-+      struct beacon_data *beacon;
-+
-+      rcu_read_lock();
-       bdev = dev_get_by_index(if_id);
-       if (bdev) {
-@@ -1738,37 +1740,35 @@
-               dev_put(bdev);
-       }
--      if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
--          !ap->beacon_head) {
-+      beacon = rcu_dereference(ap->beacon);
-+
-+      if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) {
- #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;
-+              skb = NULL;
-+              goto out;
-       }
--      /* 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 */);
-+      /* headroom, head length, tail length and maximum TIM length */
-+      skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
-+                          beacon->tail_len + 256);
-       if (!skb)
--              return NULL;
-+              goto out;
-       skb_reserve(skb, local->tx_headroom);
--      memcpy(skb_put(skb, bh_len), b_head, bh_len);
-+      memcpy(skb_put(skb, beacon->head_len), beacon->head,
-+             beacon->head_len);
-       ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
--      ieee80211_beacon_add_tim(local, ap, skb);
-+      ieee80211_beacon_add_tim(local, ap, skb, beacon);
--      if (b_tail) {
--              memcpy(skb_put(skb, bt_len), b_tail, bt_len);
--      }
-+      if (beacon->tail)
-+              memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
-+                     beacon->tail_len);
-       if (control) {
-               memset(&extra, 0, sizeof(extra));
-@@ -1781,7 +1781,8 @@
-                                      "found\n", wiphy_name(local->hw.wiphy));
-                       }
-                       dev_kfree_skb(skb);
--                      return NULL;
-+                      skb = NULL;
-+                      goto out;
-               }
-               control->tx_rate =
-@@ -1796,6 +1797,9 @@
-       }
-       ap->num_beacons++;
-+
-+ out:
-+      rcu_read_unlock();
-       return skb;
- }
- EXPORT_SYMBOL(ieee80211_beacon_get);
-@@ -1844,6 +1848,7 @@
-       struct net_device *bdev;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_ap *bss = NULL;
-+      struct beacon_data *beacon;
-       bdev = dev_get_by_index(if_id);
-       if (bdev) {
-@@ -1851,9 +1856,19 @@
-               bss = &sdata->u.ap;
-               dev_put(bdev);
-       }
--      if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
-+
-+      if (!bss)
-               return NULL;
-+      rcu_read_lock();
-+      beacon = rcu_dereference(bss->beacon);
-+
-+      if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) {
-+              rcu_read_unlock();
-+              return NULL;
-+      }
-+      rcu_read_unlock();
-+
-       if (bss->dtim_count != 0)
-               return NULL; /* send buffered bc/mc only after DTIM beacon */
-       memset(control, 0, sizeof(*control));
diff --git a/package/mac80211/patches/022-nl80211-sta.patch b/package/mac80211/patches/022-nl80211-sta.patch
deleted file mode 100644 (file)
index 4d08721..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-Subject: cfg80211/nl80211: station handling
-
-This patch adds station handling to cfg80211/nl80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   68 +++++++++++++
- include/net/cfg80211.h  |   54 ++++++++++
- net/wireless/nl80211.c  |  236 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 358 insertions(+)
-
---- everything.orig/include/linux/nl80211.h    2007-11-08 16:56:32.431522732 +0100
-+++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100
-@@ -7,6 +7,18 @@
-  */
- /**
-+ * DOC: Station handling
-+ *
-+ * Stations are added per interface, but a special case exists with VLAN
-+ * interfaces. When a station is bound to an AP interface, it may be moved
-+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
-+ * The station is still assumed to belong to the AP interface it was added
-+ * to.
-+ *
-+ * TODO: need more info?
-+ */
-+
-+/**
-  * enum nl80211_commands - supported nl80211 commands
-  *
-  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
-@@ -56,6 +68,16 @@
-  *    parameters are like for %NL80211_CMD_SET_BEACON.
-  * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
-  *
-+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
-+ *    %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
-+ *    %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
-+ *    the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
-+ *    or, if no MAC address given, all stations, on the interface identified
-+ *    by %NL80211_ATTR_IFINDEX.
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -83,6 +105,11 @@ enum nl80211_commands {
-       NL80211_CMD_NEW_BEACON,
-       NL80211_CMD_DEL_BEACON,
-+      NL80211_CMD_GET_STATION,
-+      NL80211_CMD_SET_STATION,
-+      NL80211_CMD_NEW_STATION,
-+      NL80211_CMD_DEL_STATION,
-+
-       /* add commands here */
-       /* used to define NL80211_CMD_MAX below */
-@@ -120,6 +147,17 @@ enum nl80211_commands {
-  * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
-  * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
-  *
-+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
-+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
-+ *    &enum nl80211_sta_flags.
-+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
-+ *    IEEE 802.11 7.3.1.6 (u16).
-+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
-+ *    rates as defined by IEEE 802.11 7.3.2.2 but without the length
-+ *    restriction (at most %NL80211_MAX_SUPP_RATES).
-+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
-+ *    to, or the AP interface the station was originally added to to.
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -147,12 +185,20 @@ enum nl80211_attrs {
-       NL80211_ATTR_BEACON_HEAD,
-       NL80211_ATTR_BEACON_TAIL,
-+      NL80211_ATTR_STA_AID,
-+      NL80211_ATTR_STA_FLAGS,
-+      NL80211_ATTR_STA_LISTEN_INTERVAL,
-+      NL80211_ATTR_STA_SUPPORTED_RATES,
-+      NL80211_ATTR_STA_VLAN,
-+
-       /* add attributes here, update the policy in nl80211.c */
-       __NL80211_ATTR_AFTER_LAST,
-       NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
- };
-+#define NL80211_MAX_SUPP_RATES        32
-+
- /**
-  * enum nl80211_iftype - (virtual) interface types
-  *
-@@ -184,4 +230,26 @@ enum nl80211_iftype {
-       NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
- };
-+/**
-+ * enum nl80211_sta_flags - station flags
-+ *
-+ * Station flags. When a station is added to an AP interface, it is
-+ * assumed to be already associated (and hence authenticated.)
-+ *
-+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
-+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
-+ *    with short barker preamble
-+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
-+ */
-+enum nl80211_sta_flags {
-+      __NL80211_STA_FLAG_INVALID,
-+      NL80211_STA_FLAG_AUTHORIZED,
-+      NL80211_STA_FLAG_SHORT_PREAMBLE,
-+      NL80211_STA_FLAG_WME,
-+
-+      /* keep last */
-+      __NL80211_STA_FLAG_AFTER_LAST,
-+      NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
-+};
-+
- #endif /* __LINUX_NL80211_H */
---- everything.orig/include/net/cfg80211.h     2007-11-08 16:50:38.421522842 +0100
-+++ everything/include/net/cfg80211.h  2007-11-08 17:15:15.971532444 +0100
-@@ -89,6 +89,47 @@ struct beacon_parameters {
-       int head_len, tail_len;
- };
-+/**
-+ * enum station_flags - station flags
-+ *
-+ * Station capability flags. Note that these must be the bits
-+ * according to the nl80211 flags.
-+ *
-+ * @STATION_FLAG_CHANGED: station flags were changed
-+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
-+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
-+ *    with short preambles
-+ * @STATION_FLAG_WME: station is WME/QoS capable
-+ */
-+enum station_flags {
-+      STATION_FLAG_CHANGED            = 1<<0,
-+      STATION_FLAG_AUTHORIZED         = 1<<NL80211_STA_FLAG_AUTHORIZED,
-+      STATION_FLAG_SHORT_PREAMBLE     = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
-+      STATION_FLAG_WME                = 1<<NL80211_STA_FLAG_WME,
-+};
-+
-+/**
-+ * struct station_parameters - station parameters
-+ *
-+ * Used to change and create a new station.
-+ *
-+ * @vlan: vlan interface station should belong to
-+ * @supported_rates: supported rates in IEEE 802.11 format
-+ *    (or NULL for no change)
-+ * @supported_rates_len: number of supported rates
-+ * @station_flags: station flags (see &enum station_flags)
-+ * @listen_interval: listen interval or -1 for no change
-+ * @aid: AID or zero for no change
-+ */
-+struct station_parameters {
-+      u8 *supported_rates;
-+      struct net_device *vlan;
-+      u32 station_flags;
-+      int listen_interval;
-+      u16 aid;
-+      u8 supported_rates_len;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
-@@ -130,6 +171,12 @@ struct wiphy;
-  *    interface. This should reject the call when no beacon has been
-  *    configured.
-  * @del_beacon: Remove beacon configuration and stop sending the beacon.
-+ *
-+ * @add_station: Add a new station.
-+ *
-+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
-+ *
-+ * @change_station: Modify a given station.
-  */
- struct cfg80211_ops {
-       int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -155,6 +202,13 @@ struct cfg80211_ops {
-       int     (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
-                             struct beacon_parameters *info);
-       int     (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
-+
-+      int     (*add_station)(struct wiphy *wiphy, struct net_device *dev,
-+                             u8 *mac, struct station_parameters *params);
-+      int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
-+                             u8 *mac);
-+      int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
-+                                u8 *mac, struct station_parameters *params);
- };
- #endif /* __NET_CFG80211_H */
---- everything.orig/net/wireless/nl80211.c     2007-11-08 16:58:36.711524524 +0100
-+++ everything/net/wireless/nl80211.c  2007-11-08 17:15:15.981533909 +0100
-@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
-                                      .len = IEEE80211_MAX_DATA_LEN },
-       [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
-                                      .len = IEEE80211_MAX_DATA_LEN },
-+      [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
-+      [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
-+      [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
-+      [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
-+                                             .len = NL80211_MAX_SUPP_RATES },
-+      [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
- };
- /* message building helper */
-@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
-       return err;
- }
-+static
-+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
-+      [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
-+      [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
-+      [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
-+};
-+
-+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
-+{
-+      struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
-+      int flag;
-+
-+      *staflags = 0;
-+
-+      if (!nla)
-+              return 0;
-+
-+      if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
-+                           nla, sta_flags_policy))
-+              return -EINVAL;
-+
-+      *staflags = STATION_FLAG_CHANGED;
-+
-+      for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
-+              if (flags[flag])
-+                      *staflags |= (1<<flag);
-+
-+      return 0;
-+}
-+
-+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+      return -EOPNOTSUPP;
-+}
-+
-+/*
-+ * Get vlan interface making sure it is on the right wiphy.
-+ */
-+static int get_vlan(struct nlattr *vlanattr,
-+                  struct cfg80211_registered_device *rdev,
-+                  struct net_device **vlan)
-+{
-+      *vlan = NULL;
-+
-+      if (vlanattr) {
-+              *vlan = dev_get_by_index(nla_get_u32(vlanattr));
-+              if (!*vlan)
-+                      return -ENODEV;
-+              if (!(*vlan)->ieee80211_ptr)
-+                      return -EINVAL;
-+              if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
-+                      return -EINVAL;
-+      }
-+      return 0;
-+}
-+
-+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      struct station_parameters params;
-+      u8 *mac_addr = NULL;
-+
-+      memset(&params, 0, sizeof(params));
-+
-+      params.listen_interval = -1;
-+
-+      if (info->attrs[NL80211_ATTR_STA_AID])
-+              return -EINVAL;
-+
-+      if (!info->attrs[NL80211_ATTR_MAC])
-+              return -EINVAL;
-+
-+      mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
-+              params.supported_rates =
-+                      nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+              params.supported_rates_len =
-+                      nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+      }
-+
-+      if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-+              params.listen_interval =
-+                  nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
-+
-+      if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
-+                              &params.station_flags))
-+              return -EINVAL;
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
-+      if (err)
-+              goto out;
-+
-+      if (!drv->ops->change_station) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
-+      rtnl_unlock();
-+
-+ out:
-+      if (params.vlan)
-+              dev_put(params.vlan);
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      struct station_parameters params;
-+      u8 *mac_addr = NULL;
-+
-+      memset(&params, 0, sizeof(params));
-+
-+      if (!info->attrs[NL80211_ATTR_MAC])
-+              return -EINVAL;
-+
-+      if (!info->attrs[NL80211_ATTR_STA_AID])
-+              return -EINVAL;
-+
-+      if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-+              return -EINVAL;
-+
-+      if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
-+              return -EINVAL;
-+
-+      mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+      params.supported_rates =
-+              nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+      params.supported_rates_len =
-+              nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+      params.listen_interval =
-+              nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
-+      params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
-+
-+      if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
-+                              &params.station_flags))
-+              return -EINVAL;
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
-+      if (err)
-+              goto out;
-+
-+      if (!drv->ops->add_station) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
-+      rtnl_unlock();
-+
-+ out:
-+      if (params.vlan)
-+              dev_put(params.vlan);
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
-+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      u8 *mac_addr = NULL;
-+
-+      if (info->attrs[NL80211_ATTR_MAC])
-+              mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->del_station) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
-+      rtnl_unlock();
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
-       {
-               .cmd = NL80211_CMD_GET_WIPHY,
-@@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
-               .flags = GENL_ADMIN_PERM,
-               .doit = nl80211_del_beacon,
-       },
-+      {
-+              .cmd = NL80211_CMD_GET_STATION,
-+              .doit = nl80211_get_station,
-+              /* TODO: implement dumpit */
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_SET_STATION,
-+              .doit = nl80211_set_station,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_NEW_STATION,
-+              .doit = nl80211_new_station,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
-+      {
-+              .cmd = NL80211_CMD_DEL_STATION,
-+              .doit = nl80211_del_station,
-+              .policy = nl80211_policy,
-+              .flags = GENL_ADMIN_PERM,
-+      },
- };
- /* multicast groups */
diff --git a/package/mac80211/patches/023-mac80211-implement-sta.patch b/package/mac80211/patches/023-mac80211-implement-sta.patch
deleted file mode 100644 (file)
index 0950676..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-Subject: mac80211: implement cfg80211's station handling
-
-This implements station handling from userspace via cfg80211
-in mac80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |  192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 192 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c 2007-11-08 17:11:52.351521702 +0100
-+++ everything/net/mac80211/cfg.c      2007-11-08 17:15:51.801523493 +0100
-@@ -14,6 +14,7 @@
- #include <net/cfg80211.h>
- #include "ieee80211_i.h"
- #include "cfg.h"
-+#include "ieee80211_rate.h"
- static enum ieee80211_if_types
- nl80211_type_to_mac80211_type(enum nl80211_iftype type)
-@@ -428,6 +429,194 @@ static int ieee80211_del_beacon(struct w
-       return ieee80211_if_config_beacon(dev);
- }
-+/* 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));
-+
-+static void ieee80211_send_layer2_update(struct sta_info *sta)
-+{
-+      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, sta->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 = sta->dev;
-+      skb->protocol = eth_type_trans(skb, sta->dev);
-+      memset(skb->cb, 0, sizeof(skb->cb));
-+      netif_rx(skb);
-+}
-+
-+static void sta_apply_parameters(struct ieee80211_local *local,
-+                               struct sta_info *sta,
-+                               struct station_parameters *params)
-+{
-+      u32 rates;
-+      int i, j;
-+      struct ieee80211_hw_mode *mode;
-+
-+      if (params->station_flags & STATION_FLAG_CHANGED) {
-+              sta->flags &= ~WLAN_STA_AUTHORIZED;
-+              if (params->station_flags & STATION_FLAG_AUTHORIZED)
-+                      sta->flags |= WLAN_STA_AUTHORIZED;
-+
-+              sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
-+              if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
-+                      sta->flags |= WLAN_STA_SHORT_PREAMBLE;
-+
-+              sta->flags &= ~WLAN_STA_WME;
-+              if (params->station_flags & STATION_FLAG_WME)
-+                      sta->flags |= WLAN_STA_WME;
-+      }
-+
-+      if (params->aid) {
-+              sta->aid = params->aid;
-+              if (sta->aid > IEEE80211_MAX_AID)
-+                      sta->aid = 0; /* XXX: should this be an error? */
-+      }
-+
-+      if (params->listen_interval >= 0)
-+              sta->listen_interval = params->listen_interval;
-+
-+      if (params->supported_rates) {
-+              rates = 0;
-+              mode = local->oper_hw_mode;
-+              for (i = 0; i < params->supported_rates_len; i++) {
-+                      int rate = (params->supported_rates[i] & 0x7f) * 5;
-+                      for (j = 0; j < mode->num_rates; j++) {
-+                              if (mode->rates[j].rate == rate)
-+                                      rates |= BIT(j);
-+                      }
-+              }
-+              sta->supp_rates = rates;
-+      }
-+}
-+
-+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
-+                               u8 *mac, struct station_parameters *params)
-+{
-+      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+      struct sta_info *sta;
-+      struct ieee80211_sub_if_data *sdata;
-+
-+      /* Prevent a race with changing the rate control algorithm */
-+      if (!netif_running(dev))
-+              return -ENETDOWN;
-+
-+      /* XXX: get sta belonging to dev */
-+      sta = sta_info_get(local, mac);
-+      if (sta) {
-+              sta_info_put(sta);
-+              return -EEXIST;
-+      }
-+
-+      if (params->vlan) {
-+              sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
-+
-+              if (sdata->type != IEEE80211_IF_TYPE_VLAN ||
-+                  sdata->type != IEEE80211_IF_TYPE_AP)
-+                      return -EINVAL;
-+      } else
-+              sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      sta = sta_info_add(local, dev, mac, GFP_KERNEL);
-+      if (!sta)
-+              return -ENOMEM;
-+
-+      sta->dev = sdata->dev;
-+      if (sdata->type == IEEE80211_IF_TYPE_VLAN ||
-+          sdata->type == IEEE80211_IF_TYPE_AP)
-+              ieee80211_send_layer2_update(sta);
-+
-+      sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
-+
-+      sta_apply_parameters(local, sta, params);
-+
-+      rate_control_rate_init(sta, local);
-+
-+      sta_info_put(sta);
-+
-+      return 0;
-+}
-+
-+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-+                               u8 *mac)
-+{
-+      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+      struct sta_info *sta;
-+
-+      if (mac) {
-+              /* XXX: get sta belonging to dev */
-+              sta = sta_info_get(local, mac);
-+              if (!sta)
-+                      return -ENOENT;
-+
-+              sta_info_free(sta);
-+              sta_info_put(sta);
-+      } else
-+              sta_info_flush(local, dev);
-+
-+      return 0;
-+}
-+
-+static int ieee80211_change_station(struct wiphy *wiphy,
-+                                  struct net_device *dev,
-+                                  u8 *mac,
-+                                  struct station_parameters *params)
-+{
-+      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+      struct sta_info *sta;
-+      struct ieee80211_sub_if_data *vlansdata;
-+
-+      /* XXX: get sta belonging to dev */
-+      sta = sta_info_get(local, mac);
-+      if (!sta)
-+              return -ENOENT;
-+
-+      if (params->vlan && params->vlan != sta->dev) {
-+              vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
-+
-+              if (vlansdata->type != IEEE80211_IF_TYPE_VLAN ||
-+                  vlansdata->type != IEEE80211_IF_TYPE_AP)
-+                      return -EINVAL;
-+
-+              sta->dev = params->vlan;
-+              ieee80211_send_layer2_update(sta);
-+      }
-+
-+      sta_apply_parameters(local, sta, params);
-+
-+      sta_info_put(sta);
-+
-+      return 0;
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
-       .add_virtual_intf = ieee80211_add_iface,
-       .del_virtual_intf = ieee80211_del_iface,
-@@ -439,4 +628,7 @@ struct cfg80211_ops mac80211_config_ops 
-       .add_beacon = ieee80211_add_beacon,
-       .set_beacon = ieee80211_set_beacon,
-       .del_beacon = ieee80211_del_beacon,
-+      .add_station = ieee80211_add_station,
-+      .del_station = ieee80211_del_station,
-+      .change_station = ieee80211_change_station,
- };
diff --git a/package/mac80211/patches/024-nl80211-get-sta.patch b/package/mac80211/patches/024-nl80211-get-sta.patch
deleted file mode 100644 (file)
index 198ad18..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-Subject: cfg80211/nl80211: implement station attribute retrieval
-
-After a station is added to the kernel's structures, userspace
-has to be able to retrieve statistics about that station, especially
-whether the station was idle and how much bytes were transferred
-to and from it. This adds the necessary code to nl80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   28 ++++++++++++++++
- include/net/cfg80211.h  |   35 ++++++++++++++++++++
- net/wireless/nl80211.c  |   82 +++++++++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 144 insertions(+), 1 deletion(-)
-
---- everything.orig/include/linux/nl80211.h    2007-11-08 17:15:15.961529840 +0100
-+++ everything/include/linux/nl80211.h 2007-11-08 17:17:00.891547364 +0100
-@@ -157,6 +157,9 @@ enum nl80211_commands {
-  *    restriction (at most %NL80211_MAX_SUPP_RATES).
-  * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
-  *    to, or the AP interface the station was originally added to to.
-+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
-+ *    given for %NL80211_CMD_GET_STATION, nested attribute containing
-+ *    info as possible, see &enum nl80211_sta_stats.
-  *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -190,6 +193,7 @@ enum nl80211_attrs {
-       NL80211_ATTR_STA_LISTEN_INTERVAL,
-       NL80211_ATTR_STA_SUPPORTED_RATES,
-       NL80211_ATTR_STA_VLAN,
-+      NL80211_ATTR_STA_STATS,
-       /* add attributes here, update the policy in nl80211.c */
-@@ -252,4 +256,28 @@ enum nl80211_sta_flags {
-       NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
- };
-+/**
-+ * enum nl80211_sta_stats - station statistics
-+ *
-+ * These attribute types are used with %NL80211_ATTR_STA_STATS
-+ * when getting information about a station.
-+ *
-+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
-+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
-+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
-+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
-+ * @__NL80211_STA_STAT_AFTER_LAST: internal
-+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute
-+ */
-+enum nl80211_sta_stats {
-+      __NL80211_STA_STAT_INVALID,
-+      NL80211_STA_STAT_INACTIVE_TIME,
-+      NL80211_STA_STAT_RX_BYTES,
-+      NL80211_STA_STAT_TX_BYTES,
-+
-+      /* keep last */
-+      __NL80211_STA_STAT_AFTER_LAST,
-+      NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
-+};
-+
- #endif /* __LINUX_NL80211_H */
---- everything.orig/include/net/cfg80211.h     2007-11-08 17:15:15.971532444 +0100
-+++ everything/include/net/cfg80211.h  2007-11-08 17:17:00.891547364 +0100
-@@ -130,6 +130,39 @@ struct station_parameters {
-       u8 supported_rates_len;
- };
-+/**
-+ * enum station_stats_flags - station statistics flags
-+ *
-+ * Used by the driver to indicate which info in &struct station_stats
-+ * it has filled in during get_station().
-+ *
-+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
-+ * @STATION_STAT_RX_BYTES: @rx_bytes filled
-+ * @STATION_STAT_TX_BYTES: @tx_bytes filled
-+ */
-+enum station_stats_flags {
-+      STATION_STAT_INACTIVE_TIME      = 1<<0,
-+      STATION_STAT_RX_BYTES           = 1<<1,
-+      STATION_STAT_TX_BYTES           = 1<<2,
-+};
-+
-+/**
-+ * struct station_stats - station statistics
-+ *
-+ * Station information filled by driver for get_station().
-+ *
-+ * @filled: bitflag of flags from &enum station_stats_flags
-+ * @inactive_time: time since last station activity (tx/rx) in milliseconds
-+ * @rx_bytes: bytes received from this station
-+ * @tx_bytes: bytes transmitted to this station
-+ */
-+struct station_stats {
-+      u32 filled;
-+      u32 inactive_time;
-+      u32 rx_bytes;
-+      u32 tx_bytes;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
-@@ -209,6 +242,8 @@ struct cfg80211_ops {
-                              u8 *mac);
-       int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
-                                 u8 *mac, struct station_parameters *params);
-+      int     (*get_station)(struct wiphy *wiphy, struct net_device *dev,
-+                             u8 *mac, struct station_stats *stats);
- };
- #endif /* __NET_CFG80211_H */
---- everything.orig/net/wireless/nl80211.c     2007-11-08 17:15:15.981533909 +0100
-+++ everything/net/wireless/nl80211.c  2007-11-08 17:17:00.901534235 +0100
-@@ -751,9 +751,89 @@ static int parse_station_flags(struct nl
-       return 0;
- }
-+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
-+                              int flags, struct net_device *dev,
-+                              u8 *mac_addr, struct station_stats *stats)
-+{
-+      void *hdr;
-+      struct nlattr *statsattr;
-+
-+      hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
-+      if (!hdr)
-+              return -1;
-+
-+      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-+      NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
-+
-+      statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
-+      if (!statsattr)
-+              goto nla_put_failure;
-+      if (stats->filled & STATION_STAT_INACTIVE_TIME)
-+              NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
-+                          stats->inactive_time);
-+      if (stats->filled & STATION_STAT_RX_BYTES)
-+              NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
-+                          stats->rx_bytes);
-+      if (stats->filled & STATION_STAT_TX_BYTES)
-+              NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
-+                          stats->tx_bytes);
-+
-+      nla_nest_end(msg, statsattr);
-+
-+      return genlmsg_end(msg, hdr);
-+
-+ nla_put_failure:
-+      return genlmsg_cancel(msg, hdr);
-+}
-+
-+
- static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
- {
--      return -EOPNOTSUPP;
-+      struct cfg80211_registered_device *drv;
-+      int err;
-+      struct net_device *dev;
-+      struct station_stats stats;
-+      struct sk_buff *msg;
-+      u8 *mac_addr = NULL;
-+
-+      memset(&stats, 0, sizeof(stats));
-+
-+      if (!info->attrs[NL80211_ATTR_MAC])
-+              return -EINVAL;
-+
-+      mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+      err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+      if (err)
-+              return err;
-+
-+      if (!drv->ops->get_station) {
-+              err = -EOPNOTSUPP;
-+              goto out;
-+      }
-+
-+      rtnl_lock();
-+      err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
-+      rtnl_unlock();
-+
-+      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+      if (!msg)
-+              goto out;
-+
-+      if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
-+                               dev, mac_addr, &stats) < 0)
-+              goto out_free;
-+
-+      err = genlmsg_unicast(msg, info->snd_pid);
-+      goto out;
-+
-+ out_free:
-+      nlmsg_free(msg);
-+
-+ out:
-+      cfg80211_put_dev(drv);
-+      dev_put(dev);
-+      return err;
- }
- /*
diff --git a/package/mac80211/patches/025-mac80211-get-sta.patch b/package/mac80211/patches/025-mac80211-get-sta.patch
deleted file mode 100644 (file)
index 868ca86..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-Subject: mac80211: implement station stats retrieval
-
-This implements the required cfg80211 callback in mac80211
-to allow userspace to get station statistics.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |   26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100
-+++ everything/net/mac80211/cfg.c      2007-11-08 17:17:01.921529351 +0100
-@@ -617,6 +617,31 @@ static int ieee80211_change_station(stru
-       return 0;
- }
-+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
-+                               u8 *mac, struct station_stats *stats)
-+{
-+      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+      struct sta_info *sta;
-+
-+      sta = sta_info_get(local, mac);
-+      if (!sta)
-+              return -ENOENT;
-+
-+      /* XXX: verify sta->dev == dev */
-+
-+      stats->filled = STATION_STAT_INACTIVE_TIME |
-+                      STATION_STAT_RX_BYTES |
-+                      STATION_STAT_TX_BYTES;
-+
-+      stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
-+      stats->rx_bytes = sta->rx_bytes;
-+      stats->tx_bytes = sta->tx_bytes;
-+
-+      sta_info_put(sta);
-+
-+      return 0;
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
-       .add_virtual_intf = ieee80211_add_iface,
-       .del_virtual_intf = ieee80211_del_iface,
-@@ -631,4 +656,5 @@ struct cfg80211_ops mac80211_config_ops 
-       .add_station = ieee80211_add_station,
-       .del_station = ieee80211_del_station,
-       .change_station = ieee80211_change_station,
-+      .get_station = ieee80211_get_station,
- };
index 30621c27159fda57e3946ba82a0daa0bdcea6b5a..f577c8f1c66d999bda0a1338b2170058ed7c0956 100644 (file)
@@ -54,6 +54,8 @@
 #define IEEE80211_STYPE_ACTION         0x00D0
 
 /* control */
+#define IEEE80211_STYPE_BACK_REQ       0x0080
+#define IEEE80211_STYPE_BACK           0x0090
 #define IEEE80211_STYPE_PSPOLL         0x00A0
 #define IEEE80211_STYPE_RTS            0x00B0
 #define IEEE80211_STYPE_CTS            0x00C0
 
 
 /* miscellaneous IEEE 802.11 constants */
-#define IEEE80211_MAX_FRAG_THRESHOLD   2346
-#define IEEE80211_MAX_RTS_THRESHOLD    2347
+#define IEEE80211_MAX_FRAG_THRESHOLD   2352
+#define IEEE80211_MAX_RTS_THRESHOLD    2353
 #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) */
+   802.11e clarifies the figure in section 7.1.2. The frame body is
+   up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
+#define IEEE80211_MAX_DATA_LEN         2304
+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
+#define IEEE80211_MAX_FRAME_LEN                2352
 
 #define IEEE80211_MAX_SSID_LEN         32
 
@@ -185,6 +187,25 @@ struct ieee80211_mgmt {
                                        u8 new_chan;
                                        u8 switch_count;
                                } __attribute__((packed)) chan_switch;
+                               struct{
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       __le16 capab;
+                                       __le16 timeout;
+                                       __le16 start_seq_num;
+                               } __attribute__((packed)) addba_req;
+                               struct{
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       __le16 status;
+                                       __le16 capab;
+                                       __le16 timeout;
+                               } __attribute__((packed)) addba_resp;
+                               struct{
+                                       u8 action_code;
+                                       __le16 params;
+                                       __le16 reason_code;
+                               } __attribute__((packed)) delba;
                        } u;
                } __attribute__ ((packed)) action;
        } u;
@@ -205,6 +226,72 @@ struct ieee80211_cts {
        u8 ra[6];
 } __attribute__ ((packed));
 
+/**
+ * struct ieee80211_bar - HT Block Ack Request
+ *
+ * This structure refers to "HT BlockAckReq" as
+ * described in 802.11n draft section 7.2.1.7.1
+ */
+struct ieee80211_bar {
+       __le16 frame_control;
+       __le16 duration;
+       __u8 ra[6];
+       __u8 ta[6];
+       __le16 control;
+       __le16 start_seq_num;
+} __attribute__((packed));
+
+/**
+ * struct ieee80211_ht_cap - HT capabilities
+ *
+ * This structure refers to "HT capabilities element" as
+ * described in 802.11n draft section 7.3.2.52
+ */
+struct ieee80211_ht_cap {
+       __le16 cap_info;
+       u8 ampdu_params_info;
+       u8 supp_mcs_set[16];
+       __le16 extended_ht_cap_info;
+       __le32 tx_BF_cap_info;
+       u8 antenna_selection_info;
+} __attribute__ ((packed));
+
+/**
+ * struct ieee80211_ht_cap - HT additional information
+ *
+ * This structure refers to "HT information element" as
+ * described in 802.11n draft section 7.3.2.53
+ */
+struct ieee80211_ht_addt_info {
+       u8 control_chan;
+       u8 ht_param;
+       __le16 operation_mode;
+       __le16 stbc_param;
+       u8 basic_set[16];
+} __attribute__ ((packed));
+
+/* 802.11n HT capabilities masks */
+#define IEEE80211_HT_CAP_SUP_WIDTH             0x0002
+#define IEEE80211_HT_CAP_MIMO_PS               0x000C
+#define IEEE80211_HT_CAP_GRN_FLD               0x0010
+#define IEEE80211_HT_CAP_SGI_20                        0x0020
+#define IEEE80211_HT_CAP_SGI_40                        0x0040
+#define IEEE80211_HT_CAP_DELAY_BA              0x0400
+#define IEEE80211_HT_CAP_MAX_AMSDU             0x0800
+#define IEEE80211_HT_CAP_AMPDU_FACTOR          0x03
+#define IEEE80211_HT_CAP_AMPDU_DENSITY         0x1C
+/* 802.11n HT IE masks */
+#define IEEE80211_HT_IE_CHA_SEC_OFFSET         0x03
+#define IEEE80211_HT_IE_CHA_WIDTH              0x04
+#define IEEE80211_HT_IE_HT_PROTECTION          0x0003
+#define IEEE80211_HT_IE_NON_GF_STA_PRSNT       0x0004
+#define IEEE80211_HT_IE_NON_HT_STA_PRSNT       0x0010
+
+/* MIMO Power Save Modes */
+#define WLAN_HT_CAP_MIMO_PS_STATIC         0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC        1
+#define WLAN_HT_CAP_MIMO_PS_INVALID        2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED       3
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
@@ -271,6 +358,18 @@ enum ieee80211_statuscode {
        WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
        WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
        WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+       /* 802.11e */
+       WLAN_STATUS_UNSPECIFIED_QOS = 32,
+       WLAN_STATUS_ASSOC_DENIED_NOBANDWIDTH = 33,
+       WLAN_STATUS_ASSOC_DENIED_LOWACK = 34,
+       WLAN_STATUS_ASSOC_DENIED_UNSUPP_QOS = 35,
+       WLAN_STATUS_REQUEST_DECLINED = 37,
+       WLAN_STATUS_INVALID_QOS_PARAM = 38,
+       WLAN_STATUS_CHANGE_TSPEC = 39,
+       WLAN_STATUS_WAIT_TS_DELAY = 47,
+       WLAN_STATUS_NO_DIRECT_LINK = 48,
+       WLAN_STATUS_STA_NOT_PRESENT = 49,
+       WLAN_STATUS_STA_NOT_QSTA = 50,
 };
 
 
@@ -301,6 +400,16 @@ enum ieee80211_reasoncode {
        WLAN_REASON_INVALID_RSN_IE_CAP = 22,
        WLAN_REASON_IEEE8021X_FAILED = 23,
        WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+       /* 802.11e */
+       WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32,
+       WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33,
+       WLAN_REASON_DISASSOC_LOW_ACK = 34,
+       WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP = 35,
+       WLAN_REASON_QSTA_LEAVE_QBSS = 36,
+       WLAN_REASON_QSTA_NOT_USE = 37,
+       WLAN_REASON_QSTA_REQUIRE_SETUP = 38,
+       WLAN_REASON_QSTA_TIMEOUT = 39,
+       WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45,
 };
 
 
@@ -319,6 +428,15 @@ enum ieee80211_eid {
        WLAN_EID_HP_PARAMS = 8,
        WLAN_EID_HP_TABLE = 9,
        WLAN_EID_REQUEST = 10,
+       /* 802.11e */
+       WLAN_EID_QBSS_LOAD = 11,
+       WLAN_EID_EDCA_PARAM_SET = 12,
+       WLAN_EID_TSPEC = 13,
+       WLAN_EID_TCLAS = 14,
+       WLAN_EID_SCHEDULE = 15,
+       WLAN_EID_TS_DELAY = 43,
+       WLAN_EID_TCLAS_PROCESSING = 44,
+       WLAN_EID_QOS_CAPA = 46,
        /* 802.11h */
        WLAN_EID_PWR_CONSTRAINT = 32,
        WLAN_EID_PWR_CAPABILITY = 33,
@@ -333,6 +451,9 @@ enum ieee80211_eid {
        /* 802.11g */
        WLAN_EID_ERP_INFO = 42,
        WLAN_EID_EXT_SUPP_RATES = 50,
+       /* 802.11n */
+       WLAN_EID_HT_CAPABILITY = 45,
+       WLAN_EID_HT_EXTRA_INFO = 61,
        /* 802.11i */
        WLAN_EID_RSN = 48,
        WLAN_EID_WPA = 221,
@@ -341,6 +462,32 @@ enum ieee80211_eid {
        WLAN_EID_QOS_PARAMETER = 222
 };
 
+/* Action category code */
+enum ieee80211_category {
+       WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+       WLAN_CATEGORY_QOS = 1,
+       WLAN_CATEGORY_DLS = 2,
+       WLAN_CATEGORY_BACK = 3,
+       WLAN_CATEGORY_WMM = 17,
+};
+
+/* BACK action code */
+enum ieee80211_back_actioncode {
+       WLAN_ACTION_ADDBA_REQ = 0,
+       WLAN_ACTION_ADDBA_RESP = 1,
+       WLAN_ACTION_DELBA = 2,
+};
+
+/* BACK (block-ack) parties */
+enum ieee80211_back_parties {
+       WLAN_BACK_RECIPIENT = 0,
+       WLAN_BACK_INITIATOR = 1,
+       WLAN_BACK_TIMER = 2,
+};
+
+/* A-MSDU 802.11n */
+#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080
+
 /* cipher suite selectors */
 #define WLAN_CIPHER_SUITE_USE_GROUP    0x000FAC00
 #define WLAN_CIPHER_SUITE_WEP40                0x000FAC01
index a5dd030d50e7dae03426fbcd6f3dc3ed90feb398..a9f0b93324a2aa16ceb3e9e43419a2482e099151 100644 (file)
@@ -6,6 +6,18 @@
  * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  */
 
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
 /**
  * enum nl80211_commands - supported nl80211 commands
  *
@@ -25,7 +37,7 @@
  *     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_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
  *     userspace to request deletion of a virtual interface, then requires
  *     attribute %NL80211_ATTR_IFINDEX.
  *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ *     by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
+ *     %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ *     %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ *     attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ *     or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ *     %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ *     using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ *     %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ *     parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ *     the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ *     or, if no MAC address given, all stations, on the interface identified
+ *     by %NL80211_ATTR_IFINDEX.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -54,6 +95,21 @@ enum nl80211_commands {
        NL80211_CMD_NEW_INTERFACE,
        NL80211_CMD_DEL_INTERFACE,
 
+       NL80211_CMD_GET_KEY,
+       NL80211_CMD_SET_KEY,
+       NL80211_CMD_NEW_KEY,
+       NL80211_CMD_DEL_KEY,
+
+       NL80211_CMD_GET_BEACON,
+       NL80211_CMD_SET_BEACON,
+       NL80211_CMD_NEW_BEACON,
+       NL80211_CMD_DEL_BEACON,
+
+       NL80211_CMD_GET_STATION,
+       NL80211_CMD_SET_STATION,
+       NL80211_CMD_NEW_STATION,
+       NL80211_CMD_DEL_STATION,
+
        /* add commands here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -75,6 +131,42 @@ enum nl80211_commands {
  * @NL80211_ATTR_IFNAME: network interface name
  * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
  *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *     16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *     keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *     section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *     CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *     &enum nl80211_sta_flags.
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ *     IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ *     rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ *     restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ *     to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
+ *     given for %NL80211_CMD_GET_STATION, nested attribute containing
+ *     info as possible, see &enum nl80211_sta_stats.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ *     consisting of a nested array.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -89,12 +181,38 @@ enum nl80211_attrs {
        NL80211_ATTR_IFNAME,
        NL80211_ATTR_IFTYPE,
 
+       NL80211_ATTR_MAC,
+
+       NL80211_ATTR_KEY_DATA,
+       NL80211_ATTR_KEY_IDX,
+       NL80211_ATTR_KEY_CIPHER,
+       NL80211_ATTR_KEY_SEQ,
+       NL80211_ATTR_KEY_DEFAULT,
+
+       NL80211_ATTR_BEACON_INTERVAL,
+       NL80211_ATTR_DTIM_PERIOD,
+       NL80211_ATTR_BEACON_HEAD,
+       NL80211_ATTR_BEACON_TAIL,
+
+       NL80211_ATTR_STA_AID,
+       NL80211_ATTR_STA_FLAGS,
+       NL80211_ATTR_STA_LISTEN_INTERVAL,
+       NL80211_ATTR_STA_SUPPORTED_RATES,
+       NL80211_ATTR_STA_VLAN,
+       NL80211_ATTR_STA_STATS,
+
+       NL80211_ATTR_WIPHY_BANDS,
+
+       NL80211_ATTR_MNTR_FLAGS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
        NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
+#define NL80211_MAX_SUPP_RATES 32
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -126,4 +244,139 @@ enum nl80211_iftype {
        NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *     with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ */
+enum nl80211_sta_flags {
+       __NL80211_STA_FLAG_INVALID,
+       NL80211_STA_FLAG_AUTHORIZED,
+       NL80211_STA_FLAG_SHORT_PREAMBLE,
+       NL80211_STA_FLAG_WME,
+
+       /* keep last */
+       __NL80211_STA_FLAG_AFTER_LAST,
+       NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_stats - station statistics
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_STATS
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_STAT_AFTER_LAST: internal
+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute
+ */
+enum nl80211_sta_stats {
+       __NL80211_STA_STAT_INVALID,
+       NL80211_STA_STAT_INACTIVE_TIME,
+       NL80211_STA_STAT_RX_BYTES,
+       NL80211_STA_STAT_TX_BYTES,
+
+       /* keep last */
+       __NL80211_STA_STAT_AFTER_LAST,
+       NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ *     an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ *     an array of nested bitrate attributes
+ */
+enum nl80211_band_attr {
+       __NL80211_BAND_ATTR_INVALID,
+       NL80211_BAND_ATTR_FREQS,
+       NL80211_BAND_ATTR_RATES,
+
+       /* keep last */
+       __NL80211_BAND_ATTR_AFTER_LAST,
+       NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ *     regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ *     permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ *     on this channel in current regulatory domain.
+ */
+enum nl80211_frequency_attr {
+       __NL80211_FREQUENCY_ATTR_INVALID,
+       NL80211_FREQUENCY_ATTR_FREQ,
+       NL80211_FREQUENCY_ATTR_DISABLED,
+       NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+       NL80211_FREQUENCY_ATTR_NO_IBSS,
+       NL80211_FREQUENCY_ATTR_RADAR,
+
+       /* keep last */
+       __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+       NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ *     in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+       __NL80211_BITRATE_ATTR_INVALID,
+       NL80211_BITRATE_ATTR_RATE,
+       NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+       /* keep last */
+       __NL80211_BITRATE_ATTR_AFTER_LAST,
+       NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *     overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+       __NL80211_MNTR_FLAG_INVALID,
+       NL80211_MNTR_FLAG_FCSFAIL,
+       NL80211_MNTR_FLAG_PLCPFAIL,
+       NL80211_MNTR_FLAG_CONTROL,
+       NL80211_MNTR_FLAG_OTHER_BSS,
+       NL80211_MNTR_FLAG_COOK_FRAMES,
+
+       /* keep last */
+       __NL80211_MNTR_FLAG_AFTER_LAST,
+       NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index d30960e1755c64d32bbd651b195265c1aacca0d5..ab4caf63954fae43fb426cf4406450f2a040def1 100644 (file)
@@ -49,6 +49,140 @@ extern int ieee80211_radiotap_iterator_next(
    struct ieee80211_radiotap_iterator *iterator);
 
 
+ /**
+ * struct key_params - key information
+ *
+ * Information about a key
+ *
+ * @key: key material
+ * @key_len: length of key material
+ * @cipher: cipher suite selector
+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
+ *     with the get_key() callback, must be in little endian,
+ *     length given by @seq_len.
+ */
+struct key_params {
+       u8 *key;
+       u8 *seq;
+       int key_len;
+       int seq_len;
+       u32 cipher;
+};
+
+/**
+ * struct beacon_parameters - beacon parameters
+ *
+ * Used to configure the beacon for an interface.
+ *
+ * @head: head portion of beacon (before TIM IE)
+ *     or %NULL if not changed
+ * @tail: tail portion of beacon (after TIM IE)
+ *     or %NULL if not changed
+ * @interval: beacon interval or zero if not changed
+ * @dtim_period: DTIM period or zero if not changed
+ * @head_len: length of @head
+ * @tail_len: length of @tail
+ */
+struct beacon_parameters {
+       u8 *head, *tail;
+       int interval, dtim_period;
+       int head_len, tail_len;
+};
+
+/**
+ * enum station_flags - station flags
+ *
+ * Station capability flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @STATION_FLAG_CHANGED: station flags were changed
+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *     with short preambles
+ * @STATION_FLAG_WME: station is WME/QoS capable
+ */
+enum station_flags {
+       STATION_FLAG_CHANGED            = 1<<0,
+       STATION_FLAG_AUTHORIZED         = 1<<NL80211_STA_FLAG_AUTHORIZED,
+       STATION_FLAG_SHORT_PREAMBLE     = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
+       STATION_FLAG_WME                = 1<<NL80211_STA_FLAG_WME,
+};
+
+/**
+ * struct station_parameters - station parameters
+ *
+ * Used to change and create a new station.
+ *
+ * @vlan: vlan interface station should belong to
+ * @supported_rates: supported rates in IEEE 802.11 format
+ *     (or NULL for no change)
+ * @supported_rates_len: number of supported rates
+ * @station_flags: station flags (see &enum station_flags)
+ * @listen_interval: listen interval or -1 for no change
+ * @aid: AID or zero for no change
+ */
+struct station_parameters {
+       u8 *supported_rates;
+       struct net_device *vlan;
+       u32 station_flags;
+       int listen_interval;
+       u16 aid;
+       u8 supported_rates_len;
+};
+
+/**
+ * enum station_stats_flags - station statistics flags
+ *
+ * Used by the driver to indicate which info in &struct station_stats
+ * it has filled in during get_station().
+ *
+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
+ * @STATION_STAT_RX_BYTES: @rx_bytes filled
+ * @STATION_STAT_TX_BYTES: @tx_bytes filled
+ */
+enum station_stats_flags {
+       STATION_STAT_INACTIVE_TIME      = 1<<0,
+       STATION_STAT_RX_BYTES           = 1<<1,
+       STATION_STAT_TX_BYTES           = 1<<2,
+};
+
+/**
+ * struct station_stats - station statistics
+ *
+ * Station information filled by driver for get_station().
+ *
+ * @filled: bitflag of flags from &enum station_stats_flags
+ * @inactive_time: time since last station activity (tx/rx) in milliseconds
+ * @rx_bytes: bytes received from this station
+ * @tx_bytes: bytes transmitted to this station
+ */
+struct station_stats {
+       u32 filled;
+       u32 inactive_time;
+       u32 rx_bytes;
+       u32 tx_bytes;
+};
+
+/**
+ * enum monitor_flags - monitor flags
+ *
+ * Monitor interface configuration flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @MONITOR_FLAG_CONTROL: pass control frames
+ * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
+ */
+enum monitor_flags {
+       MONITOR_FLAG_FCSFAIL            = 1<<NL80211_MNTR_FLAG_FCSFAIL,
+       MONITOR_FLAG_PLCPFAIL           = 1<<NL80211_MNTR_FLAG_PLCPFAIL,
+       MONITOR_FLAG_CONTROL            = 1<<NL80211_MNTR_FLAG_CONTROL,
+       MONITOR_FLAG_OTHER_BSS          = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
+       MONITOR_FLAG_COOK_FRAMES        = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
+};
+
 /* from net/wireless.h */
 struct wiphy;
 
@@ -71,13 +205,66 @@ struct wiphy;
  *
  * @change_virtual_intf: change type of virtual interface
  *
+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
+ *     when adding a group key.
+ *
+ * @get_key: get information about the key with the given parameters.
+ *     @mac_addr will be %NULL when requesting information for a group
+ *     key. All pointers given to the @callback function need not be valid
+ *     after it returns.
+ *
+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
+ *     and @key_index
+ *
+ * @set_default_key: set the default key on an interface
+ *
+ * @add_beacon: Add a beacon with given parameters, @head, @interval
+ *     and @dtim_period will be valid, @tail is optional.
+ * @set_beacon: Change the beacon parameters for an access point mode
+ *     interface. This should reject the call when no beacon has been
+ *     configured.
+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
+ *
+ * @add_station: Add a new station.
+ *
+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ *
+ * @change_station: Modify a given station.
  */
 struct cfg80211_ops {
        int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
-                                   enum nl80211_iftype type);
+                                   enum nl80211_iftype type, u32 *flags);
        int     (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
        int     (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
-                                      enum nl80211_iftype type);
+                                      enum nl80211_iftype type, u32 *flags);
+
+       int     (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 key_index, u8 *mac_addr,
+                          struct key_params *params);
+       int     (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 key_index, u8 *mac_addr, void *cookie,
+                          void (*callback)(void *cookie, struct key_params*));
+       int     (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 key_index, u8 *mac_addr);
+       int     (*set_default_key)(struct wiphy *wiphy,
+                                  struct net_device *netdev,
+                                  u8 key_index);
+
+       int     (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
+                             struct beacon_parameters *info);
+       int     (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
+                             struct beacon_parameters *info);
+       int     (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+
+
+       int     (*add_station)(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *mac, struct station_parameters *params);
+       int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *mac);
+       int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
+                                 u8 *mac, struct station_parameters *params);
+       int     (*get_station)(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *mac, struct station_stats *stats);
 };
 
 #endif /* __NET_CFG80211_H */
index 2b1bffbf5e72af949f777bff685d9cfd5407f34c..460da54a0019aef3fa5dcd8d5f1fc998ec29e6e4 100644 (file)
  * 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
+ * struct ieee80211_ht_bss_info - describing BSS's HT characteristics
  *
- * @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.
+ * This structure describes most essential parameters needed
+ * to describe 802.11n HT characteristics in a BSS
  *
- * @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
+ * @primary_channel: channel number of primery channel
+ * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width)
+ * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection)
  */
-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_ht_bss_info {
+       u8 primary_channel;
+       u8 bss_cap;  /* use IEEE80211_HT_IE_CHA_ */
+       u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
 };
 
 /**
@@ -208,6 +133,7 @@ struct ieee80211_tx_queue_stats_data {
  * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
  *     sent after a beacon
  * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
+ * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU
  */
 enum ieee80211_tx_queue {
        IEEE80211_TX_QUEUE_DATA0,
@@ -223,11 +149,12 @@ enum ieee80211_tx_queue {
  * 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
+       IEEE80211_TX_QUEUE_BEACON = 7,
+       NUM_TX_DATA_QUEUES_AMPDU = 16
 };
 
 struct ieee80211_tx_queue_stats {
-       struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+       struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU];
 };
 
 struct ieee80211_low_level_stats {
@@ -237,16 +164,56 @@ struct ieee80211_low_level_stats {
        unsigned int dot11RTSSuccessCount;
 };
 
+/**
+ * enum ieee80211_bss_change - BSS change notification flags
+ *
+ * These flags are used with the bss_info_changed() callback
+ * to indicate which BSS parameter changed.
+ *
+ * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated),
+ *     also implies a change in the AID.
+ * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed
+ * @BSS_CHANGED_ERP_PREAMBLE: preamble changed
+ */
+enum ieee80211_bss_change {
+       BSS_CHANGED_ASSOC               = 1<<0,
+       BSS_CHANGED_ERP_CTS_PROT        = 1<<1,
+       BSS_CHANGED_ERP_PREAMBLE        = 1<<2,
+};
+
+/**
+ * struct ieee80211_bss_conf - holds the BSS's changing parameters
+ *
+ * This structure keeps information about a BSS (and an association
+ * to that BSS) that can change during the lifetime of the BSS.
+ *
+ * @assoc: association status
+ * @aid: association ID number, valid only when @assoc is true
+ * @use_cts_prot: use CTS protection
+ * @use_short_preamble: use 802.11b short preamble
+ */
+struct ieee80211_bss_conf {
+       /* association related data */
+       bool assoc;
+       u16 aid;
+       /* erp related data */
+       bool use_cts_prot;
+       bool use_short_preamble;
+};
+
 /* 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) */
+       struct ieee80211_vif *vif;
+       struct ieee80211_rate *tx_rate;
+
+       /* Transmit rate for RTS/CTS frame */
+       struct ieee80211_rate *rts_cts_rate;
+
+       /* retry rate for the last retries */
+       struct ieee80211_rate *alt_retry_rate;
 
 #define IEEE80211_TXCTL_REQ_TX_STATUS  (1<<0)/* request TX status callback for
                                                * this frame */
@@ -265,10 +232,16 @@ struct ieee80211_tx_control {
 #define IEEE80211_TXCTL_REQUEUE                (1<<7)
 #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of
                                                * the frame */
+#define IEEE80211_TXCTL_SHORT_PREAMBLE (1<<9)
 #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send
                                                  * using the through
                                                  * set_retry_limit configured
                                                  * long retry value */
+#define IEEE80211_TXCTL_EAPOL_FRAME    (1<<11) /* internal to mac80211 */
+#define IEEE80211_TXCTL_SEND_AFTER_DTIM        (1<<12) /* send this frame after DTIM
+                                                * beacon */
+#define IEEE80211_TXCTL_AMPDU          (1<<13) /* this frame should be sent
+                                                * as part of an A-MPDU */
        u32 flags;                             /* tx control flags defined
                                                * above */
        u8 key_idx;             /* keyidx from hw->set_key(), undefined if
@@ -276,22 +249,12 @@ struct ieee80211_tx_control {
        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 */
 };
 
 
@@ -312,6 +275,8 @@ struct ieee80211_tx_control {
  *     the frame.
  * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
  *     the frame.
+ * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
+ *     is valid.
  */
 enum mac80211_rx_flags {
        RX_FLAG_MMIC_ERROR      = 1<<0,
@@ -321,6 +286,7 @@ enum mac80211_rx_flags {
        RX_FLAG_IV_STRIPPED     = 1<<4,
        RX_FLAG_FAILED_FCS_CRC  = 1<<5,
        RX_FLAG_FAILED_PLCP_CRC = 1<<6,
+       RX_FLAG_TSFT            = 1<<7,
 };
 
 /**
@@ -330,26 +296,24 @@ enum mac80211_rx_flags {
  * supported by hardware) to the 802.11 code with each received
  * frame.
  * @mactime: MAC timestamp as defined by 802.11
+ * @band: the active band when this frame was received
  * @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
+ * @rate_idx: index of data rate into band's supported rates
  * @flag: %RX_FLAG_*
  */
 struct ieee80211_rx_status {
        u64 mactime;
+       enum ieee80211_band band;
        int freq;
-       int channel;
-       enum ieee80211_phymode phymode;
        int ssi;
        int signal;
        int noise;
        int antenna;
-       int rate;
+       int rate_idx;
        int flag;
 };
 
@@ -360,12 +324,14 @@ struct ieee80211_rx_status {
  *
  * @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
+ * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
+ *     is for the whole aggregation.
  */
 enum ieee80211_tx_status_flags {
        IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
        IEEE80211_TX_STATUS_ACK         = 1<<1,
+       IEEE80211_TX_STATUS_AMPDU       = 1<<2,
 };
 
 /**
@@ -376,24 +342,25 @@ enum ieee80211_tx_status_flags {
  *
  * @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
- *
+ * @retry_count: number of retries
  * @excessive_retries: set to 1 if the frame was retried many times
  *     but not acknowledged
- *
- * @retry_count: number of retries
- *
+ * @ampdu_ack_len: number of aggregated frames.
+ *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ack_signal: signal strength of the ACK frame
  * @queue_length: ?? REMOVE
  * @queue_number: ?? REMOVE
  */
 struct ieee80211_tx_status {
        struct ieee80211_tx_control control;
        u8 flags;
-       bool excessive_retries;
        u8 retry_count;
+       bool excessive_retries;
+       u8 ampdu_ack_len;
+       u64 ampdu_ack_map;
        int ack_signal;
        int queue_length;
        int queue_number;
@@ -406,11 +373,12 @@ struct ieee80211_tx_status {
  *
  * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
  * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
- *
+ * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
  */
 enum ieee80211_conf_flags {
-       IEEE80211_CONF_SHORT_SLOT_TIME  = 1<<0,
-       IEEE80211_CONF_RADIOTAP         = 1<<1,
+       IEEE80211_CONF_SHORT_SLOT_TIME  = (1<<0),
+       IEEE80211_CONF_RADIOTAP         = (1<<1),
+       IEEE80211_CONF_SUPPORT_HT_MODE  = (1<<2),
 };
 
 /**
@@ -420,38 +388,32 @@ enum ieee80211_conf_flags {
  *
  * @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
+ * @power_level: requested transmit power (in dBm)
+ * @max_antenna_gain: maximum antenna gain (in dBi)
  * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
  *     1/2: antenna 0/1
  * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+ * @ht_conf: describes current self configuration of 802.11n HT capabilies
+ * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+ * @channel: the channel to tune to
  */
 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;
+       int power_level;
+       int max_antenna_gain;
        u8 antenna_sel_tx;
        u8 antenna_sel_rx;
+
+       struct ieee80211_channel *channel;
+
+       struct ieee80211_ht_info ht_conf;
+       struct ieee80211_ht_bss_info ht_bss_conf;
 };
 
 /**
@@ -479,14 +441,28 @@ enum ieee80211_if_types {
        IEEE80211_IF_TYPE_VLAN,
 };
 
+/**
+ * struct ieee80211_vif - per-interface data
+ *
+ * Data in this structure is continually present for driver
+ * use during the life of a virtual interface.
+ *
+ * @type: type of this virtual interface
+ * @drv_priv: data area for driver use, will always be aligned to
+ *     sizeof(void *).
+ */
+struct ieee80211_vif {
+       enum ieee80211_if_types type;
+       /* must be last */
+       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
 /**
  * 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).
+ * @vif: pointer to a driver-use per-interface structure. The pointer
+ *     itself is also used for various functions including
+ *     ieee80211_beacon_get() and ieee80211_get_buffered_bc().
  * @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
@@ -503,8 +479,8 @@ enum ieee80211_if_types {
  * in pure monitor mode.
  */
 struct ieee80211_if_init_conf {
-       int if_id;
        enum ieee80211_if_types type;
+       struct ieee80211_vif *vif;
        void *mac_addr;
 };
 
@@ -597,9 +573,6 @@ struct ieee80211_key_conf {
        u8 key[0];
 };
 
-#define IEEE80211_SEQ_COUNTER_RX       0
-#define IEEE80211_SEQ_COUNTER_TX       1
-
 /**
  * enum set_key_cmd - key command
  *
@@ -659,15 +632,19 @@ enum sta_notify_cmd {
  *     %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
+ * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE:
+ *     Hardware is not capable of short slot operation on the 2.4 GHz band.
+ *
+ * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
+ *     Hardware is not capable of receiving frames with short preamble on
+ *     the 2.4 GHz band.
  */
 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,
+       IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE          = 1<<3,
+       IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE      = 1<<4,
 };
 
 /**
@@ -679,7 +656,8 @@ enum ieee80211_hw_flags {
  * @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().
+ *     and SET_IEEE80211_PERM_ADDR(). Additionally, all supported
+ *     bands (with channels, bitrates) are registered here.
  *
  * @conf: &struct ieee80211_conf, device configuration, don't use.
  *
@@ -706,15 +684,24 @@ enum ieee80211_hw_flags {
  *
  * @queues: number of available hardware transmit queues for
  *     data packets. WMM/QoS requires at least four.
+ *
+ * @rate_control_algorithm: rate control algorithm for this hardware.
+ *     If unset (NULL), the default algorithm will be used. Must be
+ *     set before calling ieee80211_register_hw().
+ *
+ * @vif_data_size: size (in bytes) of the drv_priv data area
+ *     within &struct ieee80211_vif.
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
        struct wiphy *wiphy;
        struct workqueue_struct *workqueue;
+       const char *rate_control_algorithm;
        void *priv;
        u32 flags;
        unsigned int extra_tx_headroom;
        int channel_change_time;
+       int vif_data_size;
        u8 queues;
        s8 max_rssi;
        s8 max_signal;
@@ -854,19 +841,22 @@ enum ieee80211_filter_flags {
 };
 
 /**
- * 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_ampdu_mlme_action - A-MPDU actions
+ *
+ * These flags are used with the ampdu_action() callback in
+ * &struct ieee80211_ops to indicate which action is needed.
+ * @IEEE80211_AMPDU_RX_START: start Rx aggregation
+ * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
+ * @IEEE80211_AMPDU_TX_START: start Tx aggregation
+ * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
  */
-enum ieee80211_erp_change_flags {
-       IEEE80211_ERP_CHANGE_PROTECTION = 1<<0,
-       IEEE80211_ERP_CHANGE_PREAMBLE   = 1<<1,
+enum ieee80211_ampdu_mlme_action {
+       IEEE80211_AMPDU_RX_START,
+       IEEE80211_AMPDU_RX_STOP,
+       IEEE80211_AMPDU_TX_START,
+       IEEE80211_AMPDU_TX_STOP,
 };
 
-
 /**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
@@ -922,6 +912,14 @@ enum ieee80211_erp_change_flags {
  * @config_interface: Handler for configuration requests related to interfaces
  *     (e.g. BSSID changes.)
  *
+ * @bss_info_changed: Handler for configuration requests related to BSS
+ *     parameters that may vary during BSS's lifespan, and may affect low
+ *     level driver (e.g. assoc/disassoc status, erp parameters).
+ *     This function should not be used if no BSS has been set, unless
+ *     for association indication. The @changed parameter indicates which
+ *     of the bss parameters has changed when a call is made. This callback
+ *     has to be atomic.
+ *
  * @configure_filter: Configure the device's RX filter.
  *     See the section "Frame filtering" for more information.
  *     This callback must be implemented and atomic.
@@ -936,30 +934,16 @@ enum ieee80211_erp_change_flags {
  *     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.
+ *     the scan state machine in stack. The scan must honour the channel
+ *     configuration done by the regulatory agent in the wiphy's registered
+ *     bands.
  *
  * @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.
+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
+ *     callback should be provided to read the TKIP transmit IVs (both IV32
+ *     and IV16) for the given key from hardware.
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
  *
@@ -972,8 +956,6 @@ enum ieee80211_erp_change_flags {
  * @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.
@@ -1008,6 +990,15 @@ enum ieee80211_erp_change_flags {
  * @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.
+ *
+ * @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic.
+ *
+ * @ampdu_action: Perform a certain A-MPDU action
+ *     The RA/TID combination determines the destination and TID we want
+ *     the ampdu action to be performed for. The action is defined through
+ *     ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
+ *     is the first frame we expect to perform the action on. notice
+ *     that TX/RX_STOP can pass NULL for this parameter.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -1020,7 +1011,12 @@ struct ieee80211_ops {
                                 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);
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_if_conf *conf);
+       void (*bss_info_changed)(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_bss_conf *info,
+                                u32 changed);
        void (*configure_filter)(struct ieee80211_hw *hw,
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
@@ -1029,25 +1025,17 @@ struct ieee80211_ops {
        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);
+       void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
+                            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,
+       void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        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,
@@ -1058,6 +1046,10 @@ struct ieee80211_ops {
                             struct sk_buff *skb,
                             struct ieee80211_tx_control *control);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
+       int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+       int (*ampdu_action)(struct ieee80211_hw *hw,
+                           enum ieee80211_ampdu_mlme_action action,
+                           const u8 *addr, u16 tid, u16 *ssn);
 };
 
 /**
@@ -1089,6 +1081,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw);
 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);
+extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
 #endif
 /**
  * ieee80211_get_tx_led_name - get name of TX LED
@@ -1128,6 +1121,16 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
 #endif
 }
 
+/**
+ * ieee80211_get_assoc_led_name - get name of association LED
+ *
+ * mac80211 creates a association 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_assoc_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
@@ -1137,10 +1140,24 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 #endif
 }
 
-
-/* Register a new hardware PHYMODE capability to the stack. */
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
-                             struct ieee80211_hw_mode *mode);
+/**
+ * ieee80211_get_radio_led_name - get name of radio LED
+ *
+ * mac80211 creates a radio change 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_radio_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       return __ieee80211_get_radio_led_name(hw);
+#else
+       return NULL;
+#endif
+}
 
 /**
  * ieee80211_unregister_hw - Unregister a hardware device
@@ -1226,7 +1243,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 /**
  * ieee80211_beacon_get - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer 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
@@ -1237,13 +1254,13 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
  * is responsible of freeing it.
  */
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
-                                    int if_id,
+                                    struct ieee80211_vif *vif,
                                     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.
+ * @vif: &struct ieee80211_vif pointer 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.
@@ -1254,7 +1271,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  * 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,
+void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
                       const struct ieee80211_tx_control *frame_txctl,
                       struct ieee80211_rts *rts);
@@ -1262,7 +1279,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
 /**
  * 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.
+ * @vif: &struct ieee80211_vif pointer 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.
  *
@@ -1270,14 +1287,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
  * 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,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, 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.
+ * @vif: &struct ieee80211_vif pointer 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.
@@ -1288,7 +1305,8 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
  * 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,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
                             const void *frame, size_t frame_len,
                             const struct ieee80211_tx_control *frame_txctl,
                             struct ieee80211_cts *cts);
@@ -1296,7 +1314,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
 /**
  * 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.
+ * @vif: &struct ieee80211_vif pointer 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.
  *
@@ -1304,28 +1322,30 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
  * 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,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
                                    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.
+ * @vif: &struct ieee80211_vif pointer 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.
+ * @rate: the rate 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,
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
                                        size_t frame_len,
-                                       int rate);
+                                       struct ieee80211_rate *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.
+ * @vif: &struct ieee80211_vif pointer 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
@@ -1344,7 +1364,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
  * use common code for all beacons.
  */
 struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                          struct ieee80211_tx_control *control);
 
 /**
@@ -1422,8 +1442,96 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
  */
 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]
+/**
+ * ieee80211_iterate_active_interfaces - iterate active interfaces
+ *
+ * This function iterates over the interfaces associated with a given
+ * hardware that are currently active and calls the callback for them.
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
+                                        void (*iterator)(void *data, u8 *mac,
+                                               struct ieee80211_vif *vif),
+                                        void *data);
+
+/**
+ * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to BA on.
+ * @return: success if addBA request was sent, failure otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to start aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ */
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ * This version of the function is irq safe.
+ */
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+                                     u16 tid);
+
+/**
+ * ieee80211_stop_tx_ba_session - Stop a Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to stop BA.
+ * @initiator: if indicates initiator DELBA frame will be sent.
+ * @return: error if no sta with matching da found, success otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to stop aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+                                u8 *ra, u16 tid,
+                                enum ieee80211_back_parties initiator);
+
+/**
+ * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ */
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
+
+/**
+ * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ * This version of the function is irq safe.
+ */
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+                                    u16 tid);
 
 #endif /* MAC80211_H */
diff --git a/package/mac80211/src/include/net/wireless.h b/package/mac80211/src/include/net/wireless.h
new file mode 100644 (file)
index 0000000..c7f805e
--- /dev/null
@@ -0,0 +1,307 @@
+#ifndef __NET_WIRELESS_H
+#define __NET_WIRELESS_H
+
+/*
+ * 802.11 device management
+ *
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <net/cfg80211.h>
+
+/**
+ * enum ieee80211_band - supported frequency bands
+ *
+ * The bands are assigned this way because the supported
+ * bitrates differ in these bands.
+ *
+ * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
+ * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
+ */
+enum ieee80211_band {
+       IEEE80211_BAND_2GHZ,
+       IEEE80211_BAND_5GHZ,
+
+       /* keep last */
+       IEEE80211_NUM_BANDS
+};
+
+/**
+ * enum ieee80211_channel_flags - channel flags
+ *
+ * Channel flags set by the regulatory control code.
+ *
+ * @IEEE80211_CHAN_DISABLED: This channel is disabled.
+ * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
+ *     on this channel.
+ * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ */
+enum ieee80211_channel_flags {
+       IEEE80211_CHAN_DISABLED         = 1<<0,
+       IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
+       IEEE80211_CHAN_NO_IBSS          = 1<<2,
+       IEEE80211_CHAN_RADAR            = 1<<3,
+};
+
+/**
+ * struct ieee80211_channel - channel definition
+ *
+ * This structure describes a single channel for use
+ * with cfg80211.
+ *
+ * @center_freq: center frequency in MHz
+ * @hw_value: hardware-specific value for the channel
+ * @flags: channel flags from &enum ieee80211_channel_flags.
+ * @orig_flags: channel flags at registration time, used by regulatory
+ *     code to support devices with additional restrictions
+ * @band: band this channel belongs to.
+ * @max_antenna_gain: maximum antenna gain in dBi
+ * @max_power: maximum transmission power (in dBm)
+ * @orig_mag: internal use
+ * @orig_mpwr: internal use
+ */
+struct ieee80211_channel {
+       enum ieee80211_band band;
+       u16 center_freq;
+       u16 hw_value;
+       u32 flags;
+       int max_antenna_gain;
+       int max_power;
+       u32 orig_flags;
+       int orig_mag, orig_mpwr;
+};
+
+/**
+ * enum ieee80211_rate_flags - rate flags
+ *
+ * Hardware/specification flags for rates. These are structured
+ * in a way that allows using the same bitrate structure for
+ * different bands/PHY modes.
+ *
+ * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short
+ *     preamble on this bitrate; only relevant in 2.4GHz band and
+ *     with CCK rates.
+ * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate
+ *     when used with 802.11a (on the 5 GHz band); filled by the
+ *     core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate
+ *     when used with 802.11b (on the 2.4 GHz band); filled by the
+ *     core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate
+ *     when used with 802.11g (on the 2.4 GHz band); filled by the
+ *     core code when registering the wiphy.
+ * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode.
+ */
+enum ieee80211_rate_flags {
+       IEEE80211_RATE_SHORT_PREAMBLE   = 1<<0,
+       IEEE80211_RATE_MANDATORY_A      = 1<<1,
+       IEEE80211_RATE_MANDATORY_B      = 1<<2,
+       IEEE80211_RATE_MANDATORY_G      = 1<<3,
+       IEEE80211_RATE_ERP_G            = 1<<4,
+};
+
+/**
+ * struct ieee80211_rate - bitrate definition
+ *
+ * This structure describes a bitrate that an 802.11 PHY can
+ * operate with. The two values @hw_value and @hw_value_short
+ * are only for driver use when pointers to this structure are
+ * passed around.
+ *
+ * @flags: rate-specific flags
+ * @bitrate: bitrate in units of 100 Kbps
+ * @hw_value: driver/hardware value for this rate
+ * @hw_value_short: driver/hardware value for this rate when
+ *     short preamble is used
+ */
+struct ieee80211_rate {
+       u32 flags;
+       u16 bitrate;
+       u16 hw_value, hw_value_short;
+};
+
+/**
+ * struct ieee80211_ht_info - describing STA's HT capabilities
+ *
+ * This structure describes most essential parameters needed
+ * to describe 802.11n HT capabilities for an STA.
+ *
+ * @ht_supported: is HT supported by STA, 0: no, 1: yes
+ * @cap: HT capabilities map as described in 802.11n spec
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
+ * @supp_mcs_set: Supported MCS set as described in 802.11n spec
+ */
+struct ieee80211_ht_info {
+       u16 cap; /* use IEEE80211_HT_CAP_ */
+       u8 ht_supported;
+       u8 ampdu_factor;
+       u8 ampdu_density;
+       u8 supp_mcs_set[16];
+};
+
+/**
+ * struct ieee80211_supported_band - frequency band definition
+ *
+ * This structure describes a frequency band a wiphy
+ * is able to operate in.
+ *
+ * @channels: Array of channels the hardware can operate in
+ *     in this band.
+ * @band: the band this structure represents
+ * @n_channels: Number of channels in @channels
+ * @bitrates: Array of bitrates the hardware can operate with
+ *     in this band. Must be sorted to give a valid "supported
+ *     rates" IE, i.e. CCK rates first, then OFDM.
+ * @n_bitrates: Number of bitrates in @bitrates
+ */
+struct ieee80211_supported_band {
+       struct ieee80211_channel *channels;
+       struct ieee80211_rate *bitrates;
+       enum ieee80211_band band;
+       int n_channels;
+       int n_bitrates;
+       struct ieee80211_ht_info ht_info;
+};
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ */
+struct wiphy {
+       /* assign these fields before you register the wiphy */
+
+       /* permanent MAC address */
+       u8 perm_addr[ETH_ALEN];
+
+       /* If multiple wiphys are registered and you're handed e.g.
+        * a regular netdev with assigned ieee80211_ptr, you won't
+        * know whether it points to a wiphy your driver has registered
+        * or not. Assign this to something global to your driver to
+        * help determine whether you own this wiphy or not. */
+       void *privid;
+
+       struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+
+       /* fields below are read-only, assigned by cfg80211 */
+
+       /* the item in /sys/class/ieee80211/ points to this,
+        * you need use set_wiphy_dev() (see below) */
+       struct device dev;
+
+       /* dir in debugfs: ieee80211/<wiphyname> */
+       struct dentry *debugfsdir;
+
+       char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+/** struct wireless_dev - wireless per-netdev state
+ *
+ * This structure must be allocated by the driver/stack
+ * that uses the ieee80211_ptr field in struct net_device
+ * (this is intentional so it can be allocated along with
+ * the netdev.)
+ *
+ * @wiphy: pointer to hardware description
+ */
+struct wireless_dev {
+       struct wiphy *wiphy;
+
+       /* private to the generic wireless code */
+       struct list_head list;
+       struct net_device *netdev;
+};
+
+/**
+ * wiphy_priv - return priv from wiphy
+ */
+static inline void *wiphy_priv(struct wiphy *wiphy)
+{
+       BUG_ON(!wiphy);
+       return &wiphy->priv;
+}
+
+/**
+ * set_wiphy_dev - set device pointer for wiphy
+ */
+static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
+{
+       wiphy->dev.parent = dev;
+}
+
+/**
+ * wiphy_dev - get wiphy dev pointer
+ */
+static inline struct device *wiphy_dev(struct wiphy *wiphy)
+{
+       return wiphy->dev.parent;
+}
+
+/**
+ * wiphy_name - get wiphy name
+ */
+static inline char *wiphy_name(struct wiphy *wiphy)
+{
+       return wiphy->dev.bus_id;
+}
+
+/**
+ * wdev_priv - return wiphy priv from wireless_dev
+ */
+static inline void *wdev_priv(struct wireless_dev *wdev)
+{
+       BUG_ON(!wdev);
+       return wiphy_priv(wdev->wiphy);
+}
+
+/**
+ * wiphy_new - create a new wiphy for use with cfg80211
+ *
+ * create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * the returned pointer must be assigned to each netdev's
+ * ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
+
+/**
+ * wiphy_register - register a wiphy with cfg80211
+ *
+ * register the given wiphy
+ *
+ * Returns a non-negative wiphy index or a negative error code.
+ */
+extern int wiphy_register(struct wiphy *wiphy);
+
+/**
+ * wiphy_unregister - deregister a wiphy from cfg80211
+ *
+ * unregister a device with the given priv pointer.
+ * After this call, no more requests can be made with this priv
+ * pointer, but the call may sleep to wait for an outstanding
+ * request that is being handled.
+ */
+extern void wiphy_unregister(struct wiphy *wiphy);
+
+/**
+ * wiphy_free - free wiphy
+ */
+extern void wiphy_free(struct wiphy *wiphy);
+
+/**
+ * ieee80211_channel_to_frequency - convert channel number to frequency
+ */
+extern int ieee80211_channel_to_frequency(int chan);
+
+/**
+ * ieee80211_frequency_to_channel - convert frequency to channel number
+ */
+extern int ieee80211_frequency_to_channel(int freq);
+
+#endif /* __NET_WIRELESS_H */
index 6fffb3845ab6c76b341819376def9f1c77e68424..45c7c0c3875e808beb1ad1085a213955d6ca8235 100644 (file)
@@ -1,6 +1,5 @@
 config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
-       depends on EXPERIMENTAL
        select CRYPTO
        select CRYPTO_ECB
        select CRYPTO_ARC4
@@ -10,15 +9,84 @@ config MAC80211
        select CFG80211
        select NET_SCH_FIFO
        ---help---
-       This option enables the hardware independent IEEE 802.11
-       networking stack.
+         This option enables the hardware independent IEEE 802.11
+         networking stack.
+
+menu "Rate control algorithm selection"
+       depends on MAC80211 != n
+
+choice
+       prompt "Default rate control algorithm"
+       default MAC80211_RC_DEFAULT_PID
+       ---help---
+         This option selects the default rate control algorithm
+         mac80211 will use. Note that this default can still be
+         overriden through the ieee80211_default_rc_algo module
+         parameter if different algorithms are available.
+
+config MAC80211_RC_DEFAULT_PID
+       bool "PID controller based rate control algorithm"
+       select MAC80211_RC_PID
+       ---help---
+         Select the PID controller based rate control as the
+         default rate control algorithm. You should choose
+         this unless you know what you are doing.
+
+config MAC80211_RC_DEFAULT_SIMPLE
+       bool "Simple rate control algorithm"
+       select MAC80211_RC_SIMPLE
+       ---help---
+         Select the simple rate control as the default rate
+         control algorithm. Note that this is a non-responsive,
+         dumb algorithm. You should choose the PID rate control
+         instead.
+
+config MAC80211_RC_DEFAULT_NONE
+       bool "No default algorithm"
+       depends on EMBEDDED
+       help
+         Selecting this option will select no default algorithm
+         and allow you to not build any. Do not choose this
+         option unless you know your driver comes with another
+         suitable algorithm.
+endchoice
+
+comment "Selecting 'y' for an algorithm will"
+comment "build the algorithm into mac80211."
+
+config MAC80211_RC_DEFAULT
+       string
+       default "pid" if MAC80211_RC_DEFAULT_PID
+       default "simple" if MAC80211_RC_DEFAULT_SIMPLE
+       default ""
+
+config MAC80211_RC_PID
+       tristate "PID controller based rate control algorithm"
+       ---help---
+         This option enables a TX rate control algorithm for
+         mac80211 that uses a PID controller to select the TX
+         rate.
+
+         Say Y or M unless you're sure you want to use a
+         different rate control algorithm.
+
+config MAC80211_RC_SIMPLE
+       tristate "Simple rate control algorithm (DEPRECATED)"
+       ---help---
+         This option enables a very simple, non-responsive TX
+         rate control algorithm. This algorithm is deprecated
+         and will be removed from the kernel in the near future.
+         It has been replaced by the PID algorithm.
+
+         Say N unless you know what you are doing.
+endmenu
 
 config MAC80211_LEDS
        bool "Enable LED triggers"
        depends on MAC80211 && LEDS_TRIGGERS
        ---help---
-       This option enables a few LED triggers for different
-       packet receive/transmit events.
+         This option enables a few LED triggers for different
+         packet receive/transmit events.
 
 config MAC80211_DEBUGFS
        bool "Export mac80211 internals in DebugFS"
@@ -29,6 +97,18 @@ config MAC80211_DEBUGFS
 
          Say N unless you know you need this.
 
+config MAC80211_DEBUG_PACKET_ALIGNMENT
+       bool "Enable packet alignment debugging"
+       depends on MAC80211
+       help
+         This option is recommended for driver authors and strongly
+         discouraged for everybody else, it will trigger a warning
+         when a driver hands mac80211 a buffer that is aligned in
+         a way that will cause problems with the IP stack on some
+         architectures.
+
+         Say N unless you're writing a mac80211 based driver.
+
 config MAC80211_DEBUG
        bool "Enable debugging output"
        depends on MAC80211
@@ -39,6 +119,16 @@ config MAC80211_DEBUG
          If you are not trying to debug or develop the ieee80211
          subsystem, you most likely want to say N here.
 
+config MAC80211_HT_DEBUG
+       bool "Enable HT debugging output"
+       depends on MAC80211_DEBUG
+       ---help---
+         This option enables 802.11n High Throughput features
+         debug tracing output.
+
+         If you are not trying to debug of develop the ieee80211
+         subsystem, you most likely want to say N here.
+
 config MAC80211_VERBOSE_DEBUG
        bool "Verbose debugging output"
        depends on MAC80211_DEBUG
index 219cd9f9341fe099bc0ce5ba69c2da7442339ab8..9d7a19581a295a8c0d8a495ced04f9ee449dfad8 100644 (file)
@@ -1,10 +1,15 @@
-obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
+obj-$(CONFIG_MAC80211) += mac80211.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
+# objects for PID algorithm
+rc80211_pid-y := rc80211_pid_algo.o
+rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
 
-mac80211-objs := \
+# build helper for PID algorithm
+rc-pid-y := $(rc80211_pid-y)
+rc-pid-m := rc80211_pid.o
+
+# mac80211 objects
+mac80211-y := \
        ieee80211.o \
        ieee80211_ioctl.o \
        sta_info.o \
@@ -14,7 +19,6 @@ mac80211-objs := \
        ieee80211_iface.o \
        ieee80211_rate.o \
        michael.o \
-       regdomain.o \
        tkip.o \
        aes_ccm.o \
        cfg.o \
@@ -22,5 +26,22 @@ mac80211-objs := \
        tx.o \
        key.o \
        util.o \
-       event.o \
-       $(mac80211-objs-y)
+       event.o
+
+mac80211-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
+mac80211-$(CONFIG_NET_SCHED) += wme.o
+mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
+       debugfs.o \
+       debugfs_sta.o \
+       debugfs_netdev.o \
+       debugfs_key.o
+
+
+# Build rate control algorithm(s)
+CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
+CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE
+mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
+mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID))
+
+# Modular rate algorithms are assigned to mac80211-m - make separate modules
+obj-m += $(mac80211-m)
index e55569bee7d081c6a827883cbd900784a7e27066..e62fe55944b88774233059b247038be252d5844a 100644 (file)
@@ -7,10 +7,10 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
-#include <asm/scatterlist.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_key.h"
@@ -63,7 +63,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
        s_0 = scratch + AES_BLOCK_LEN;
        e = scratch + 2 * AES_BLOCK_LEN;
 
-       num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
        last_len = data_len % AES_BLOCK_LEN;
        aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
 
@@ -102,7 +102,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
        s_0 = scratch + AES_BLOCK_LEN;
        a = scratch + 2 * AES_BLOCK_LEN;
 
-       num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
        last_len = data_len % AES_BLOCK_LEN;
        aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
 
index cd78b3f29c98ca9a80e0b7f280ebc493000e53f1..a083cc78855edc39b51eb011bf1cd6c430a1c4f2 100644 (file)
@@ -1,16 +1,20 @@
 /*
  * mac80211 configuration hooks for cfg80211
  *
- * Copyright 2006      Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007        Johannes Berg <johannes@sipsolutions.net>
  *
  * This file is GPLv2 as found in COPYING.
  */
 
+#include <linux/ieee80211.h>
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
+#include <linux/rcupdate.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
 #include "cfg.h"
+#include "ieee80211_rate.h"
 
 static enum ieee80211_if_types
 nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -30,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
 }
 
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-                              enum nl80211_iftype type)
+                              enum nl80211_iftype type, u32 *flags)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        enum ieee80211_if_types itype;
+       struct net_device *dev;
+       struct ieee80211_sub_if_data *sdata;
+       int err;
 
        if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
                return -ENODEV;
@@ -42,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
        if (itype == IEEE80211_IF_TYPE_INVALID)
                return -EINVAL;
 
-       return ieee80211_if_add(local->mdev, name, NULL, itype);
+       err = ieee80211_if_add(local->mdev, name, &dev, itype);
+       if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+               return err;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       sdata->u.mntr_flags = *flags;
+       return 0;
 }
 
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
@@ -55,7 +68,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
                return -ENODEV;
 
        /* we're under RTNL */
-       dev = __dev_get_by_index(ifindex);
+       dev = __dev_get_by_index(&init_net, ifindex);
        if (!dev)
                return 0;
 
@@ -65,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 }
 
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
-                                 enum nl80211_iftype type)
+                                 enum nl80211_iftype type, u32 *flags)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct net_device *dev;
@@ -76,7 +89,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
                return -ENODEV;
 
        /* we're under RTNL */
-       dev = __dev_get_by_index(ifindex);
+       dev = __dev_get_by_index(&init_net, ifindex);
        if (!dev)
                return -ENODEV;
 
@@ -89,12 +102,551 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-        if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
                return -EOPNOTSUPP;
 
        ieee80211_if_reinit(dev);
        ieee80211_if_set_type(dev, itype);
 
+       if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+               return 0;
+
+       sdata->u.mntr_flags = *flags;
+       return 0;
+}
+
+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+                            u8 key_idx, u8 *mac_addr,
+                            struct key_params *params)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta = NULL;
+       enum ieee80211_key_alg alg;
+       int ret;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       switch (params->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               alg = ALG_WEP;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               alg = ALG_TKIP;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               alg = ALG_CCMP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (mac_addr) {
+               sta = sta_info_get(sdata->local, mac_addr);
+               if (!sta)
+                       return -ENOENT;
+       }
+
+       ret = 0;
+       if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
+                                params->key_len, params->key))
+               ret = -ENOMEM;
+
+       if (sta)
+               sta_info_put(sta);
+
+       return ret;
+}
+
+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+                            u8 key_idx, u8 *mac_addr)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
+       int ret;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (mac_addr) {
+               sta = sta_info_get(sdata->local, mac_addr);
+               if (!sta)
+                       return -ENOENT;
+
+               ret = 0;
+               if (sta->key)
+                       ieee80211_key_free(sta->key);
+               else
+                       ret = -ENOENT;
+
+               sta_info_put(sta);
+               return ret;
+       }
+
+       if (!sdata->keys[key_idx])
+               return -ENOENT;
+
+       ieee80211_key_free(sdata->keys[key_idx]);
+
+       return 0;
+}
+
+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+                            u8 key_idx, u8 *mac_addr, void *cookie,
+                            void (*callback)(void *cookie,
+                                             struct key_params *params))
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct sta_info *sta = NULL;
+       u8 seq[6] = {0};
+       struct key_params params;
+       struct ieee80211_key *key;
+       u32 iv32;
+       u16 iv16;
+       int err = -ENOENT;
+
+       if (mac_addr) {
+               sta = sta_info_get(sdata->local, mac_addr);
+               if (!sta)
+                       goto out;
+
+               key = sta->key;
+       } else
+               key = sdata->keys[key_idx];
+
+       if (!key)
+               goto out;
+
+       memset(&params, 0, sizeof(params));
+
+       switch (key->conf.alg) {
+       case ALG_TKIP:
+               params.cipher = WLAN_CIPHER_SUITE_TKIP;
+
+               iv32 = key->u.tkip.iv32;
+               iv16 = key->u.tkip.iv16;
+
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   sdata->local->ops->get_tkip_seq)
+                       sdata->local->ops->get_tkip_seq(
+                               local_to_hw(sdata->local),
+                               key->conf.hw_key_idx,
+                               &iv32, &iv16);
+
+               seq[0] = iv16 & 0xff;
+               seq[1] = (iv16 >> 8) & 0xff;
+               seq[2] = iv32 & 0xff;
+               seq[3] = (iv32 >> 8) & 0xff;
+               seq[4] = (iv32 >> 16) & 0xff;
+               seq[5] = (iv32 >> 24) & 0xff;
+               params.seq = seq;
+               params.seq_len = 6;
+               break;
+       case ALG_CCMP:
+               params.cipher = WLAN_CIPHER_SUITE_CCMP;
+               seq[0] = key->u.ccmp.tx_pn[5];
+               seq[1] = key->u.ccmp.tx_pn[4];
+               seq[2] = key->u.ccmp.tx_pn[3];
+               seq[3] = key->u.ccmp.tx_pn[2];
+               seq[4] = key->u.ccmp.tx_pn[1];
+               seq[5] = key->u.ccmp.tx_pn[0];
+               params.seq = seq;
+               params.seq_len = 6;
+               break;
+       case ALG_WEP:
+               if (key->conf.keylen == 5)
+                       params.cipher = WLAN_CIPHER_SUITE_WEP40;
+               else
+                       params.cipher = WLAN_CIPHER_SUITE_WEP104;
+               break;
+       }
+
+       params.key = key->conf.key;
+       params.key_len = key->conf.keylen;
+
+       callback(cookie, &params);
+       err = 0;
+
+ out:
+       if (sta)
+               sta_info_put(sta);
+       return err;
+}
+
+static int ieee80211_config_default_key(struct wiphy *wiphy,
+                                       struct net_device *dev,
+                                       u8 key_idx)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       ieee80211_set_default_key(sdata, key_idx);
+
+       return 0;
+}
+
+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+                                u8 *mac, struct station_stats *stats)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+
+       sta = sta_info_get(local, mac);
+       if (!sta)
+               return -ENOENT;
+
+       /* XXX: verify sta->dev == dev */
+
+       stats->filled = STATION_STAT_INACTIVE_TIME |
+                       STATION_STAT_RX_BYTES |
+                       STATION_STAT_TX_BYTES;
+
+       stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+       stats->rx_bytes = sta->rx_bytes;
+       stats->tx_bytes = sta->tx_bytes;
+
+       sta_info_put(sta);
+
+       return 0;
+}
+
+/*
+ * This handles both adding a beacon and setting new beacon info
+ */
+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
+                                  struct beacon_parameters *params)
+{
+       struct beacon_data *new, *old;
+       int new_head_len, new_tail_len;
+       int size;
+       int err = -EINVAL;
+
+       old = sdata->u.ap.beacon;
+
+       /* head must not be zero-length */
+       if (params->head && !params->head_len)
+               return -EINVAL;
+
+       /*
+        * This is a kludge. beacon interval should really be part
+        * of the beacon information.
+        */
+       if (params->interval) {
+               sdata->local->hw.conf.beacon_int = params->interval;
+               if (ieee80211_hw_config(sdata->local))
+                       return -EINVAL;
+               /*
+                * We updated some parameter so if below bails out
+                * it's not an error.
+                */
+               err = 0;
+       }
+
+       /* Need to have a beacon head if we don't have one yet */
+       if (!params->head && !old)
+               return err;
+
+       /* sorry, no way to start beaconing without dtim period */
+       if (!params->dtim_period && !old)
+               return err;
+
+       /* new or old head? */
+       if (params->head)
+               new_head_len = params->head_len;
+       else
+               new_head_len = old->head_len;
+
+       /* new or old tail? */
+       if (params->tail || !old)
+               /* params->tail_len will be zero for !params->tail */
+               new_tail_len = params->tail_len;
+       else
+               new_tail_len = old->tail_len;
+
+       size = sizeof(*new) + new_head_len + new_tail_len;
+
+       new = kzalloc(size, GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       /* start filling the new info now */
+
+       /* new or old dtim period? */
+       if (params->dtim_period)
+               new->dtim_period = params->dtim_period;
+       else
+               new->dtim_period = old->dtim_period;
+
+       /*
+        * pointers go into the block we allocated,
+        * memory is | beacon_data | head | tail |
+        */
+       new->head = ((u8 *) new) + sizeof(*new);
+       new->tail = new->head + new_head_len;
+       new->head_len = new_head_len;
+       new->tail_len = new_tail_len;
+
+       /* copy in head */
+       if (params->head)
+               memcpy(new->head, params->head, new_head_len);
+       else
+               memcpy(new->head, old->head, new_head_len);
+
+       /* copy in optional tail */
+       if (params->tail)
+               memcpy(new->tail, params->tail, new_tail_len);
+       else
+               if (old)
+                       memcpy(new->tail, old->tail, new_tail_len);
+
+       rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+       synchronize_rcu();
+
+       kfree(old);
+
+       return ieee80211_if_config_beacon(sdata->dev);
+}
+
+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+                               struct beacon_parameters *params)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct beacon_data *old;
+
+       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+               return -EINVAL;
+
+       old = sdata->u.ap.beacon;
+
+       if (old)
+               return -EALREADY;
+
+       return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+                               struct beacon_parameters *params)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct beacon_data *old;
+
+       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+               return -EINVAL;
+
+       old = sdata->u.ap.beacon;
+
+       if (!old)
+               return -ENOENT;
+
+       return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct beacon_data *old;
+
+       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+               return -EINVAL;
+
+       old = sdata->u.ap.beacon;
+
+       if (!old)
+               return -ENOENT;
+
+       rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+       synchronize_rcu();
+       kfree(old);
+
+       return ieee80211_if_config_beacon(dev);
+}
+
+/* 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));
+
+static void ieee80211_send_layer2_update(struct sta_info *sta)
+{
+       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, sta->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 = sta->dev;
+       skb->protocol = eth_type_trans(skb, sta->dev);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       netif_rx(skb);
+}
+
+static void sta_apply_parameters(struct ieee80211_local *local,
+                                struct sta_info *sta,
+                                struct station_parameters *params)
+{
+       u32 rates;
+       int i, j;
+       struct ieee80211_supported_band *sband;
+
+       if (params->station_flags & STATION_FLAG_CHANGED) {
+               sta->flags &= ~WLAN_STA_AUTHORIZED;
+               if (params->station_flags & STATION_FLAG_AUTHORIZED)
+                       sta->flags |= WLAN_STA_AUTHORIZED;
+
+               sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+               if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
+                       sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+
+               sta->flags &= ~WLAN_STA_WME;
+               if (params->station_flags & STATION_FLAG_WME)
+                       sta->flags |= WLAN_STA_WME;
+       }
+
+       if (params->aid) {
+               sta->aid = params->aid;
+               if (sta->aid > IEEE80211_MAX_AID)
+                       sta->aid = 0; /* XXX: should this be an error? */
+       }
+
+       if (params->listen_interval >= 0)
+               sta->listen_interval = params->listen_interval;
+
+       if (params->supported_rates) {
+               rates = 0;
+               sband = local->hw.wiphy->bands[local->oper_channel->band];
+
+               for (i = 0; i < params->supported_rates_len; i++) {
+                       int rate = (params->supported_rates[i] & 0x7f) * 5;
+                       for (j = 0; j < sband->n_bitrates; j++) {
+                               if (sband->bitrates[j].bitrate == rate)
+                                       rates |= BIT(j);
+                       }
+               }
+               sta->supp_rates[local->oper_channel->band] = rates;
+       }
+}
+
+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
+                                u8 *mac, struct station_parameters *params)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       struct ieee80211_sub_if_data *sdata;
+
+       /* Prevent a race with changing the rate control algorithm */
+       if (!netif_running(dev))
+               return -ENETDOWN;
+
+       /* XXX: get sta belonging to dev */
+       sta = sta_info_get(local, mac);
+       if (sta) {
+               sta_info_put(sta);
+               return -EEXIST;
+       }
+
+       if (params->vlan) {
+               sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+               if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+                   sdata->vif.type != IEEE80211_IF_TYPE_AP)
+                       return -EINVAL;
+       } else
+               sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+       if (!sta)
+               return -ENOMEM;
+
+       sta->dev = sdata->dev;
+       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+           sdata->vif.type == IEEE80211_IF_TYPE_AP)
+               ieee80211_send_layer2_update(sta);
+
+       sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+       sta_apply_parameters(local, sta, params);
+
+       rate_control_rate_init(sta, local);
+
+       sta_info_put(sta);
+
+       return 0;
+}
+
+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+                                u8 *mac)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+
+       if (mac) {
+               /* XXX: get sta belonging to dev */
+               sta = sta_info_get(local, mac);
+               if (!sta)
+                       return -ENOENT;
+
+               sta_info_free(sta);
+               sta_info_put(sta);
+       } else
+               sta_info_flush(local, dev);
+
+       return 0;
+}
+
+static int ieee80211_change_station(struct wiphy *wiphy,
+                                   struct net_device *dev,
+                                   u8 *mac,
+                                   struct station_parameters *params)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       struct ieee80211_sub_if_data *vlansdata;
+
+       /* XXX: get sta belonging to dev */
+       sta = sta_info_get(local, mac);
+       if (!sta)
+               return -ENOENT;
+
+       if (params->vlan && params->vlan != sta->dev) {
+               vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+               if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+                   vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
+                       return -EINVAL;
+
+               sta->dev = params->vlan;
+               ieee80211_send_layer2_update(sta);
+       }
+
+       sta_apply_parameters(local, sta, params);
+
+       sta_info_put(sta);
+
        return 0;
 }
 
@@ -102,4 +654,15 @@ struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
        .change_virtual_intf = ieee80211_change_iface,
+       .add_key = ieee80211_add_key,
+       .del_key = ieee80211_del_key,
+       .get_key = ieee80211_get_key,
+       .set_default_key = ieee80211_config_default_key,
+       .add_beacon = ieee80211_add_beacon,
+       .set_beacon = ieee80211_set_beacon,
+       .del_beacon = ieee80211_del_beacon,
+       .add_station = ieee80211_add_station,
+       .del_station = ieee80211_del_station,
+       .change_station = ieee80211_change_station,
+       .get_station = ieee80211_get_station,
 };
index 60514b2c97b99c845eac2020a9f865557a59f170..4736c64937b4d0eafa03cb463fb14248e34139de 100644 (file)
@@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file)
        return 0;
 }
 
-static const char *ieee80211_mode_str(int mode)
-{
-       switch (mode) {
-       case MODE_IEEE80211A:
-               return "IEEE 802.11a";
-       case MODE_IEEE80211B:
-               return "IEEE 802.11b";
-       case MODE_IEEE80211G:
-               return "IEEE 802.11g";
-       default:
-               return "UNKNOWN";
-       }
-}
-
-static ssize_t modes_read(struct file *file, char __user *userbuf,
-                         size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       struct ieee80211_hw_mode *mode;
-       char buf[150], *p = buf;
-
-       /* FIXME: locking! */
-       list_for_each_entry(mode, &local->modes_list, list) {
-               p += scnprintf(p, sizeof(buf)+buf-p,
-                              "%s\n", ieee80211_mode_str(mode->mode));
-       }
-
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations modes_ops = {
-       .read = modes_read,
-       .open = mac80211_open_file_generic,
-};
-
 #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)                 \
@@ -80,10 +45,8 @@ static const struct file_operations name## _ops = {                  \
        local->debugfs.name = NULL;
 
 
-DEBUGFS_READONLY_FILE(channel, 20, "%d",
-                     local->hw.conf.channel);
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
-                     local->hw.conf.freq);
+                     local->hw.conf.channel->center_freq);
 DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
                      local->hw.conf.antenna_sel_tx);
 DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
@@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
                      local->long_retry_limit);
 DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
                      local->total_ps_buffered);
-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(rate_ctrl_alg, 100, "%s",
@@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        local->debugfs.stations = debugfs_create_dir("stations", phyd);
        local->debugfs.keys = debugfs_create_dir("keys", phyd);
 
-       DEBUGFS_ADD(channel);
        DEBUGFS_ADD(frequency);
        DEBUGFS_ADD(antenna_sel_tx);
        DEBUGFS_ADD(antenna_sel_rx);
@@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(short_retry_limit);
        DEBUGFS_ADD(long_retry_limit);
        DEBUGFS_ADD(total_ps_buffered);
-       DEBUGFS_ADD(mode);
        DEBUGFS_ADD(wep_iv);
-       DEBUGFS_ADD(modes);
 
        statsd = debugfs_create_dir("statistics", phyd);
        local->debugfs.statistics = statsd;
@@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
 
 void debugfs_hw_del(struct ieee80211_local *local)
 {
-       DEBUGFS_DEL(channel);
        DEBUGFS_DEL(frequency);
        DEBUGFS_DEL(antenna_sel_tx);
        DEBUGFS_DEL(antenna_sel_rx);
@@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
        DEBUGFS_DEL(short_retry_limit);
        DEBUGFS_DEL(long_retry_limit);
        DEBUGFS_DEL(total_ps_buffered);
-       DEBUGFS_DEL(mode);
        DEBUGFS_DEL(wep_iv);
-       DEBUGFS_DEL(modes);
 
        DEBUGFS_STATS_DEL(transmitted_fragment_count);
        DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
index 8e4a1bcd16ea3cf4466759c2216cc7f0ce3a35ca..c881524c87251ca39a02717663538f381248a836 100644 (file)
@@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
                                    struct sta_info *sta)
 {
        char buf[50];
+       DECLARE_MAC_BUF(mac);
 
        if (!key->debugfs.dir)
                return;
 
-       sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr));
+       sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr));
        key->debugfs.stalink =
                debugfs_create_symlink("station", key->debugfs.dir, buf);
 }
index 2b5e7615e5091d00c41d13b6ceb7a21b1d07b061..29f7b98ba1fb277e7c9e9cb88efbd1ecaef9e7c6 100644 (file)
@@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name(                                       \
        const struct ieee80211_sub_if_data *sdata, char *buf,           \
        int buflen)                                                     \
 {                                                                      \
-       return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\
+       DECLARE_MAC_BUF(mac);                                           \
+       return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
 }
 
 #define __IEEE80211_IF_FILE(name)                                      \
@@ -90,8 +91,6 @@ static const struct file_operations name##_ops = {                    \
 /* common attributes */
 IEEE80211_IF_FILE(channel_use, channel_use, DEC);
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
-IEEE80211_IF_FILE(eapol, eapol, DEC);
-IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
 
 /* STA/IBSS attributes */
 IEEE80211_IF_FILE(state, u.sta.state, DEC);
@@ -118,13 +117,12 @@ static ssize_t ieee80211_if_fmt_flags(
                 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" : "");
+                sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
 }
 __IEEE80211_IF_FILE(flags);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
-IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
 IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
@@ -138,26 +136,6 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 }
 __IEEE80211_IF_FILE(num_buffered_multicast);
 
-static ssize_t ieee80211_if_fmt_beacon_head_len(
-       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-       if (sdata->u.ap.beacon_head)
-               return scnprintf(buf, buflen, "%d\n",
-                                sdata->u.ap.beacon_head_len);
-       return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_head_len);
-
-static ssize_t ieee80211_if_fmt_beacon_tail_len(
-       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-       if (sdata->u.ap.beacon_tail)
-               return scnprintf(buf, buflen, "%d\n",
-                                sdata->u.ap.beacon_tail_len);
-       return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_tail_len);
-
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
@@ -169,8 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(channel_use, sta);
        DEBUGFS_ADD(drop_unencrypted, sta);
-       DEBUGFS_ADD(eapol, sta);
-       DEBUGFS_ADD(ieee8021_x, sta);
        DEBUGFS_ADD(state, sta);
        DEBUGFS_ADD(bssid, sta);
        DEBUGFS_ADD(prev_bssid, sta);
@@ -191,25 +167,18 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(channel_use, ap);
        DEBUGFS_ADD(drop_unencrypted, ap);
-       DEBUGFS_ADD(eapol, ap);
-       DEBUGFS_ADD(ieee8021_x, ap);
        DEBUGFS_ADD(num_sta_ps, ap);
-       DEBUGFS_ADD(dtim_period, ap);
        DEBUGFS_ADD(dtim_count, ap);
        DEBUGFS_ADD(num_beacons, ap);
        DEBUGFS_ADD(force_unicast_rateidx, ap);
        DEBUGFS_ADD(max_ratectrl_rateidx, ap);
        DEBUGFS_ADD(num_buffered_multicast, ap);
-       DEBUGFS_ADD(beacon_head_len, ap);
-       DEBUGFS_ADD(beacon_tail_len, ap);
 }
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(channel_use, wds);
        DEBUGFS_ADD(drop_unencrypted, wds);
-       DEBUGFS_ADD(eapol, wds);
-       DEBUGFS_ADD(ieee8021_x, wds);
        DEBUGFS_ADD(peer, wds);
 }
 
@@ -217,8 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(channel_use, vlan);
        DEBUGFS_ADD(drop_unencrypted, vlan);
-       DEBUGFS_ADD(eapol, vlan);
-       DEBUGFS_ADD(ieee8021_x, vlan);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -230,7 +197,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
        if (!sdata->debugfsdir)
                return;
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_STA:
        case IEEE80211_IF_TYPE_IBSS:
                add_sta_files(sdata);
@@ -262,8 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_DEL(channel_use, sta);
        DEBUGFS_DEL(drop_unencrypted, sta);
-       DEBUGFS_DEL(eapol, sta);
-       DEBUGFS_DEL(ieee8021_x, sta);
        DEBUGFS_DEL(state, sta);
        DEBUGFS_DEL(bssid, sta);
        DEBUGFS_DEL(prev_bssid, sta);
@@ -284,25 +249,18 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_DEL(channel_use, ap);
        DEBUGFS_DEL(drop_unencrypted, ap);
-       DEBUGFS_DEL(eapol, ap);
-       DEBUGFS_DEL(ieee8021_x, ap);
        DEBUGFS_DEL(num_sta_ps, ap);
-       DEBUGFS_DEL(dtim_period, ap);
        DEBUGFS_DEL(dtim_count, ap);
        DEBUGFS_DEL(num_beacons, ap);
        DEBUGFS_DEL(force_unicast_rateidx, ap);
        DEBUGFS_DEL(max_ratectrl_rateidx, ap);
        DEBUGFS_DEL(num_buffered_multicast, ap);
-       DEBUGFS_DEL(beacon_head_len, ap);
-       DEBUGFS_DEL(beacon_tail_len, ap);
 }
 
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_DEL(channel_use, wds);
        DEBUGFS_DEL(drop_unencrypted, wds);
-       DEBUGFS_DEL(eapol, wds);
-       DEBUGFS_DEL(ieee8021_x, wds);
        DEBUGFS_DEL(peer, wds);
 }
 
@@ -310,8 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_DEL(channel_use, vlan);
        DEBUGFS_DEL(drop_unencrypted, vlan);
-       DEBUGFS_DEL(eapol, vlan);
-       DEBUGFS_DEL(ieee8021_x, vlan);
 }
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -361,7 +317,7 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 {
-       del_files(sdata, sdata->type);
+       del_files(sdata, sdata->vif.type);
        debugfs_remove(sdata->debugfsdir);
        sdata->debugfsdir = NULL;
 }
index 4ea0ea7ea040421583c6193553995359f46aa66e..ac61353ae7cedde1e2682629bc9d21da5b8cd00c 100644 (file)
@@ -33,25 +33,16 @@ static ssize_t sta_ ##name## _read(struct file *file,                       \
 #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
 #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
 
-#define STA_READ_RATE(name, field)                                     \
-static ssize_t sta_##name##_read(struct file *file,                    \
-                                char __user *userbuf,                  \
-                                size_t count, loff_t *ppos)            \
-{                                                                      \
-       struct sta_info *sta = file->private_data;                      \
-       struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
-       struct ieee80211_hw_mode *mode = local->oper_hw_mode;           \
-       char buf[20];                                                   \
-       int res = scnprintf(buf, sizeof(buf), "%d\n",                   \
-                           (sta->field >= 0 &&                         \
-                           sta->field < mode->num_rates) ?             \
-                           mode->rates[sta->field].rate : -1);         \
-       return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+#define STA_OPS(name)                                                  \
+static const struct file_operations sta_ ##name## _ops = {             \
+       .read = sta_##name##_read,                                      \
+       .open = mac80211_open_file_generic,                             \
 }
 
-#define STA_OPS(name)                                                  \
+#define STA_OPS_WR(name)                                               \
 static const struct file_operations sta_ ##name## _ops = {             \
        .read = sta_##name##_read,                                      \
+       .write = sta_##name##_write,                                    \
        .open = mac80211_open_file_generic,                             \
 }
 
@@ -70,8 +61,6 @@ STA_FILE(rx_fragments, rx_fragments, LU);
 STA_FILE(rx_dropped, rx_dropped, LU);
 STA_FILE(tx_fragments, tx_fragments, LU);
 STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(txrate, txrate, RATE);
-STA_FILE(last_txrate, last_txrate, RATE);
 STA_FILE(tx_retry_failed, tx_retry_failed, LU);
 STA_FILE(tx_retry_count, tx_retry_count, LU);
 STA_FILE(last_rssi, last_rssi, D);
@@ -85,12 +74,11 @@ 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",
+       int res = scnprintf(buf, sizeof(buf), "%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" : "",
                sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
-               sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
                sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
                sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
                sta->flags & WLAN_STA_WME ? "WME\n" : "",
@@ -191,6 +179,113 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
 STA_OPS(wme_tx_queue);
 #endif
 
+static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
+                                       size_t count, loff_t *ppos)
+{
+       char buf[768], *p = buf;
+       int i;
+       struct sta_info *sta = file->private_data;
+       p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
+       p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
+                       "TIDs info is: \n TID :",
+                       (sta->ampdu_mlme.dialog_token_allocator + 1));
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n RX  :");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+       sta->ampdu_mlme.tid_rx[i].state);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+                       sta->ampdu_mlme.tid_rx[i].dialog_token);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+                       sta->ampdu_mlme.tid_tx[i].state);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+                       sta->ampdu_mlme.tid_tx[i].dialog_token);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+                       sta->ampdu_mlme.tid_tx[i].ssn);
+
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t sta_agg_status_write(struct file *file,
+               const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       struct sta_info *sta = file->private_data;
+       struct net_device *dev = sta->dev;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hw *hw = &local->hw;
+       u8 *da = sta->addr;
+       static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0};
+       static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
+                                       1, 1, 1, 1, 1, 1, 1, 1};
+       char *endp;
+       char buf[32];
+       int buf_size, rs;
+       unsigned int tid_num;
+       char state[4];
+
+       memset(buf, 0x00, sizeof(buf));
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       tid_num = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EINVAL;
+
+       if ((tid_num >= 100) && (tid_num <= 115)) {
+               /* toggle Rx aggregation command */
+               tid_num = tid_num - 100;
+               if (tid_static_rx[tid_num] == 1) {
+                       strcpy(state, "off ");
+                       ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0,
+                                       WLAN_REASON_QSTA_REQUIRE_SETUP);
+                       sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF;
+                       tid_static_rx[tid_num] = 0;
+               } else {
+                       strcpy(state, "on ");
+                       sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00;
+                       tid_static_rx[tid_num] = 1;
+               }
+               printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
+                               tid_num, state);
+       } else if ((tid_num >= 0) && (tid_num <= 15)) {
+               /* toggle Tx aggregation command */
+               if (tid_static_tx[tid_num] == 0) {
+                       strcpy(state, "on ");
+                       rs =  ieee80211_start_tx_ba_session(hw, da, tid_num);
+                       if (rs == 0)
+                               tid_static_tx[tid_num] = 1;
+               } else {
+                       strcpy(state, "off");
+                       rs =  ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
+                       if (rs == 0)
+                               tid_static_tx[tid_num] = 0;
+               }
+               printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
+                               tid_num, state, rs);
+       }
+
+       return count;
+}
+STA_OPS_WR(agg_status);
+
 #define DEBUGFS_ADD(name) \
        sta->debugfs.name = debugfs_create_file(#name, 0444, \
                sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -202,15 +297,15 @@ STA_OPS(wme_tx_queue);
 
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
-       char buf[3*6];
        struct dentry *stations_dir = sta->local->debugfs.stations;
+       DECLARE_MAC_BUF(mac);
 
        if (!stations_dir)
                return;
 
-       sprintf(buf, MAC_FMT, MAC_ARG(sta->addr));
+       print_mac(mac, sta->addr);
 
-       sta->debugfs.dir = debugfs_create_dir(buf, stations_dir);
+       sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
        if (!sta->debugfs.dir)
                return;
 
@@ -224,6 +319,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(wme_rx_queue);
        DEBUGFS_ADD(wme_tx_queue);
 #endif
+       DEBUGFS_ADD(agg_status);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
@@ -238,6 +334,7 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
        DEBUGFS_DEL(wme_rx_queue);
        DEBUGFS_DEL(wme_tx_queue);
 #endif
+       DEBUGFS_DEL(agg_status);
 
        debugfs_remove(sta->debugfs.dir);
        sta->debugfs.dir = NULL;
index 68a526cb76234af06d3684304172c559ae23e875..2280f40b4560ba3c963cc84f35e73a543bb47064 100644 (file)
@@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
 {
        union iwreq_data wrqu;
        char *buf = kmalloc(128, GFP_ATOMIC);
+       DECLARE_MAC_BUF(mac);
 
        if (buf) {
                /* TODO: needed parameters: count, key type, TSC */
                sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-                       "keyid=%d %scast addr=" MAC_FMT ")",
+                       "keyid=%d %scast addr=%s)",
                        keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
-                       MAC_ARG(hdr->addr2));
+                       print_mac(mac, hdr->addr2));
                memset(&wrqu, 0, sizeof(wrqu));
                wrqu.data.length = strlen(buf);
                wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
index 64fa7204b447ae2de8928af6b2c3f726ddf79f3d..1a0171d2f1f0c3fa9f73dfe7f027b36d5ffd8bd2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/wireless.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
+#include <net/net_namespace.h>
 #include <net/cfg80211.h>
 
 #include "ieee80211_i.h"
@@ -33,6 +34,8 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
+#define SUPP_MCS_SET_LEN 16
+
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -45,7 +48,7 @@ struct ieee80211_tx_status_rtap_hdr {
 
 /* common interface routines */
 
-static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
 {
        memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
        return ETH_ALEN;
@@ -64,9 +67,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local)
                new_flags |= FIF_ALLMULTI;
 
        if (local->monitors)
-               new_flags |= FIF_CONTROL |
-                            FIF_OTHER_BSS |
-                            FIF_BCN_PRBRESP_PROMISC;
+               new_flags |= FIF_BCN_PRBRESP_PROMISC;
+
+       if (local->fif_fcsfail)
+               new_flags |= FIF_FCSFAIL;
+
+       if (local->fif_plcpfail)
+               new_flags |= FIF_PLCPFAIL;
+
+       if (local->fif_control)
+               new_flags |= FIF_CONTROL;
+
+       if (local->fif_other_bss)
+               new_flags |= FIF_OTHER_BSS;
 
        changed_flags = local->filter_flags ^ new_flags;
 
@@ -174,21 +187,21 @@ static int ieee80211_open(struct net_device *dev)
                        /*
                         * check whether it may have the same address
                         */
-                       if (!identical_mac_addr_allowed(sdata->type,
-                                                       nsdata->type))
+                       if (!identical_mac_addr_allowed(sdata->vif.type,
+                                                       nsdata->vif.type))
                                return -ENOTUNIQ;
 
                        /*
                         * can only add VLANs to enabled APs
                         */
-                       if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
-                           nsdata->type == IEEE80211_IF_TYPE_AP &&
+                       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
+                           nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
                            netif_running(nsdata->dev))
                                sdata->u.vlan.ap = nsdata;
                }
        }
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_WDS:
                if (is_zero_ether_addr(sdata->u.wds.remote_addr))
                        return -ENOLINK;
@@ -215,32 +228,46 @@ static int ieee80211_open(struct net_device *dev)
                        res = local->ops->start(local_to_hw(local));
                if (res)
                        return res;
+               ieee80211_hw_config(local);
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
-       switch (sdata->type) {
+       switch (sdata->vif.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:
+               if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+                       local->cooked_mntrs++;
+                       break;
+               }
+
                /* 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);
-
+               if (local->monitors == 1)
                        local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-                       ieee80211_hw_config(local);
-               }
+
+               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+                       local->fif_fcsfail++;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+                       local->fif_plcpfail++;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+                       local->fif_control++;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+                       local->fif_other_bss++;
+
+               netif_tx_lock_bh(local->mdev);
+               ieee80211_configure_filter(local);
+               netif_tx_unlock_bh(local->mdev);
                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.vif = &sdata->vif;
+               conf.type = sdata->vif.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)
@@ -252,7 +279,7 @@ static int ieee80211_open(struct net_device *dev)
                ieee80211_reset_erp_info(dev);
                ieee80211_enable_keys(sdata);
 
-               if (sdata->type == IEEE80211_IF_TYPE_STA &&
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
                        netif_carrier_off(dev);
                else
@@ -266,6 +293,17 @@ static int ieee80211_open(struct net_device *dev)
                tasklet_enable(&local->tasklet);
        }
 
+       /*
+        * set_multicast_list will be invoked by the networking core
+        * which will check whether any increments here were done in
+        * error and sync them down to the hardware as filter flags.
+        */
+       if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+               atomic_inc(&local->iff_allmultis);
+
+       if (sdata->flags & IEEE80211_SDATA_PROMISC)
+               atomic_inc(&local->iff_promiscs);
+
        local->open_count++;
 
        netif_start_queue(dev);
@@ -278,17 +316,47 @@ static int ieee80211_stop(struct net_device *dev)
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_if_init_conf conf;
+       struct sta_info *sta;
+       int i;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       list_for_each_entry(sta, &local->sta_list, list) {
+               if (sta->dev == dev)
+                       for (i = 0; i <  STA_TID_NUM; i++)
+                               ieee80211_sta_stop_rx_ba_session(sta->dev,
+                                               sta->addr, i,
+                                               WLAN_BACK_RECIPIENT,
+                                               WLAN_REASON_QSTA_LEAVE_QBSS);
+       }
+
        netif_stop_queue(dev);
 
+       /*
+        * Don't count this interface for promisc/allmulti while it
+        * is down. dev_mc_unsync() will invoke set_multicast_list
+        * on the master interface which will sync these down to the
+        * hardware as filter flags.
+        */
+       if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+               atomic_dec(&local->iff_allmultis);
+
+       if (sdata->flags & IEEE80211_SDATA_PROMISC)
+               atomic_dec(&local->iff_promiscs);
+
        dev_mc_unsync(local->mdev, dev);
 
-       /* down all dependent devices, that is VLANs */
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+       /* APs need special treatment */
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmp;
+               struct beacon_data *old_beacon = sdata->u.ap.beacon;
+
+               /* remove beacon */
+               rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+               synchronize_rcu();
+               kfree(old_beacon);
 
+               /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
                                         u.vlan.list)
                        dev_close(vlan->dev);
@@ -297,22 +365,34 @@ static int ieee80211_stop(struct net_device *dev)
 
        local->open_count--;
 
-       switch (sdata->type) {
+       switch (sdata->vif.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);
-
-                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-                       ieee80211_hw_config(local);
+               if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+                       local->cooked_mntrs--;
+                       break;
                }
+
+               local->monitors--;
+               if (local->monitors == 0)
+                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+
+               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+                       local->fif_fcsfail--;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+                       local->fif_plcpfail--;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+                       local->fif_control--;
+               if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+                       local->fif_other_bss--;
+
+               netif_tx_lock_bh(local->mdev);
+               ieee80211_configure_filter(local);
+               netif_tx_unlock_bh(local->mdev);
                break;
        case IEEE80211_IF_TYPE_STA:
        case IEEE80211_IF_TYPE_IBSS:
@@ -327,16 +407,24 @@ static int ieee80211_stop(struct net_device *dev)
                synchronize_rcu();
                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);
+               if (local->scan_dev == sdata->dev) {
+                       if (!local->ops->hw_scan) {
+                               local->sta_sw_scanning = 0;
+                               cancel_delayed_work(&local->scan_work);
+                       } else
+                               local->sta_hw_scanning = 0;
                }
+
                flush_workqueue(local->hw.workqueue);
+
+               sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+               kfree(sdata->u.sta.extra_ie);
+               sdata->u.sta.extra_ie = NULL;
+               sdata->u.sta.extra_ie_len = 0;
                /* fall through */
        default:
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
+               conf.vif = &sdata->vif;
+               conf.type = sdata->vif.type;
                conf.mac_addr = dev->dev_addr;
                /* disable all keys for as long as this netdev is down */
                ieee80211_disable_keys(sdata);
@@ -350,6 +438,8 @@ static int ieee80211_stop(struct net_device *dev)
                if (local->ops->stop)
                        local->ops->stop(local_to_hw(local));
 
+               ieee80211_led_radio(local, 0);
+
                tasklet_disable(&local->tx_pending_tasklet);
                tasklet_disable(&local->tasklet);
        }
@@ -357,6 +447,329 @@ static int ieee80211_stop(struct net_device *dev)
        return 0;
 }
 
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sta_info *sta;
+       struct ieee80211_sub_if_data *sdata;
+       u16 start_seq_num = 0;
+       u8 *state;
+       int ret;
+       DECLARE_MAC_BUF(mac);
+
+       if (tid >= STA_TID_NUM)
+               return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
+                               print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+       sta = sta_info_get(local, ra);
+       if (!sta) {
+               printk(KERN_DEBUG "Could not find the station\n");
+               return -ENOENT;
+       }
+
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+       /* we have tried too many times, receiver does not want A-MPDU */
+       if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) {
+               ret = -EBUSY;
+               goto start_ba_exit;
+       }
+
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       /* check if the TID is not in aggregation flow already */
+       if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "BA request denied - session is not "
+                                "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ret = -EAGAIN;
+               goto start_ba_exit;
+       }
+
+       /* ensure that TX flow won't interrupt us
+        * until the end of the call to requeue function */
+       spin_lock_bh(&local->mdev->queue_lock);
+
+       /* create a new queue for this aggregation */
+       ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+       /* case no queue is available to aggregation
+        * don't switch to aggregation */
+       if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "BA request denied - no queue available for"
+                                       " tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               spin_unlock_bh(&local->mdev->queue_lock);
+               goto start_ba_exit;
+       }
+       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+       /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+        * call back right away, it must see that the flow has begun */
+       *state |= HT_ADDBA_REQUESTED_MSK;
+
+       if (local->ops->ampdu_action)
+               ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+                                               ra, tid, &start_seq_num);
+
+       if (ret) {
+               /* No need to requeue the packets in the agg queue, since we
+                * held the tx lock: no packet could be enqueued to the newly
+                * allocated queue */
+                ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "BA request denied - HW or queue unavailable"
+                               " for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               spin_unlock_bh(&local->mdev->queue_lock);
+               *state = HT_AGG_STATE_IDLE;
+               goto start_ba_exit;
+       }
+
+       /* Will put all the packets in the new SW queue */
+       ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+       spin_unlock_bh(&local->mdev->queue_lock);
+
+       /* We have most probably almost emptied the legacy queue */
+       /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */
+
+       /* send an addBA request */
+       sta->ampdu_mlme.dialog_token_allocator++;
+       sta->ampdu_mlme.tid_tx[tid].dialog_token =
+                       sta->ampdu_mlme.dialog_token_allocator;
+       sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num;
+
+       ieee80211_send_addba_request(sta->dev, ra, tid,
+                        sta->ampdu_mlme.tid_tx[tid].dialog_token,
+                        sta->ampdu_mlme.tid_tx[tid].ssn,
+                        0x40, 5000);
+
+       /* activate the timer for the recipient's addBA response */
+       sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires =
+                               jiffies + ADDBA_RESP_INTERVAL;
+       add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+       printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+
+start_ba_exit:
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       sta_info_put(sta);
+       return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+                                u8 *ra, u16 tid,
+                                enum ieee80211_back_parties initiator)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sta_info *sta;
+       u8 *state;
+       int ret = 0;
+       DECLARE_MAC_BUF(mac);
+
+       if (tid >= STA_TID_NUM)
+               return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n",
+                               print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+       sta = sta_info_get(local, ra);
+       if (!sta)
+               return -ENOENT;
+
+       /* check if the TID is in aggregation */
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+       if (*state != HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "Try to stop Tx aggregation on"
+                               " non active TID\n");
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ret = -ENOENT;
+               goto stop_BA_exit;
+       }
+
+       ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+       *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+               (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+       if (local->ops->ampdu_action)
+               ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+                                               ra, tid, NULL);
+
+       /* case HW denied going back to legacy */
+       if (ret) {
+               WARN_ON(ret != -EBUSY);
+               *state = HT_AGG_STATE_OPERATIONAL;
+               ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               goto stop_BA_exit;
+       }
+
+stop_BA_exit:
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       sta_info_put(sta);
+       return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sta_info *sta;
+       u8 *state;
+       DECLARE_MAC_BUF(mac);
+
+       if (tid >= STA_TID_NUM) {
+               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+                               tid, STA_TID_NUM);
+               return;
+       }
+
+       sta = sta_info_get(local, ra);
+       if (!sta) {
+               printk(KERN_DEBUG "Could not find station: %s\n",
+                               print_mac(mac, ra));
+               return;
+       }
+
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+       if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+               printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+                               *state);
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               sta_info_put(sta);
+               return;
+       }
+
+       WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+       *state |= HT_ADDBA_DRV_READY_MSK;
+
+       if (*state == HT_AGG_STATE_OPERATIONAL) {
+               printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+               ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+       }
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       sta_info_put(sta);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sta_info *sta;
+       u8 *state;
+       int agg_queue;
+       DECLARE_MAC_BUF(mac);
+
+       if (tid >= STA_TID_NUM) {
+               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+                               tid, STA_TID_NUM);
+               return;
+       }
+
+       printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n",
+                               print_mac(mac, ra), tid);
+
+       sta = sta_info_get(local, ra);
+       if (!sta) {
+               printk(KERN_DEBUG "Could not find station: %s\n",
+                               print_mac(mac, ra));
+               return;
+       }
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+               printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+               sta_info_put(sta);
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               return;
+       }
+
+       if (*state & HT_AGG_STATE_INITIATOR_MSK)
+               ieee80211_send_delba(sta->dev, ra, tid,
+                       WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+       agg_queue = sta->tid_to_tx_q[tid];
+
+       /* avoid ordering issues: we are the only one that can modify
+        * the content of the qdiscs */
+       spin_lock_bh(&local->mdev->queue_lock);
+       /* remove the queue for this aggregation */
+       ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+       spin_unlock_bh(&local->mdev->queue_lock);
+
+       /* we just requeued the all the frames that were in the removed
+        * queue, and since we might miss a softirq we do netif_schedule.
+        * ieee80211_wake_queue is not used here as this queue is not
+        * necessarily stopped */
+       netif_schedule(local->mdev);
+       *state = HT_AGG_STATE_IDLE;
+       sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+       sta_info_put(sta);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+                                     const u8 *ra, u16 tid)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_ra_tid *ra_tid;
+       struct sk_buff *skb = dev_alloc_skb(0);
+
+       if (unlikely(!skb)) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "%s: Not enough memory, "
+                              "dropping start BA session", skb->dev->name);
+               return;
+       }
+       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+       memcpy(&ra_tid->ra, ra, ETH_ALEN);
+       ra_tid->tid = tid;
+
+       skb->pkt_type = IEEE80211_ADDBA_MSG;
+       skb_queue_tail(&local->skb_queue, skb);
+       tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+                                    const u8 *ra, u16 tid)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_ra_tid *ra_tid;
+       struct sk_buff *skb = dev_alloc_skb(0);
+
+       if (unlikely(!skb)) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "%s: Not enough memory, "
+                              "dropping stop BA session", skb->dev->name);
+               return;
+       }
+       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+       memcpy(&ra_tid->ra, ra, ETH_ALEN);
+       ra_tid->tid = tid;
+
+       skb->pkt_type = IEEE80211_DELBA_MSG;
+       skb_queue_tail(&local->skb_queue, skb);
+       tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
 static void ieee80211_set_multicast_list(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -365,8 +778,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 
        allmulti = !!(dev->flags & IFF_ALLMULTI);
        promisc = !!(dev->flags & IFF_PROMISC);
-       sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
-       sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+       sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+       sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
 
        if (allmulti != sdata_allmulti) {
                if (dev->flags & IFF_ALLMULTI)
@@ -387,6 +800,14 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
        dev_mc_sync(local->mdev, dev);
 }
 
+static const struct header_ops ieee80211_header_ops = {
+       .create         = eth_header,
+       .parse          = header_parse_80211,
+       .rebuild        = eth_rebuild_header,
+       .cache          = eth_header_cache,
+       .cache_update   = eth_header_cache_update,
+};
+
 /* Must not be called for mdev */
 void ieee80211_if_setup(struct net_device *dev)
 {
@@ -407,6 +828,7 @@ 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;
+       DECLARE_MAC_BUF(mac);
 
        if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
                return 0;
@@ -415,6 +837,9 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
        sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
        if (!sta)
                return -ENOMEM;
+
+       sta->flags |= WLAN_STA_AUTHORIZED;
+
        sta_info_put(sta);
 
        /* Remove STA entry for the old peer */
@@ -424,8 +849,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
                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));
+                      "peer %s\n",
+                      dev->name, print_mac(mac, sdata->u.wds.remote_addr));
        }
 
        /* Update WDS link data */
@@ -448,20 +873,20 @@ static int __ieee80211_if_config(struct net_device *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) {
+       conf.type = sdata->vif.type;
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.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) {
+       } else if (sdata->vif.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);
+                                           &sdata->vif, &conf);
 }
 
 int ieee80211_if_config(struct net_device *dev)
@@ -473,11 +898,13 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_tx_control control;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        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);
+       skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
+                                  &control);
        if (!skb)
                return -ENOMEM;
        return __ieee80211_if_config(dev, skb, &control);
@@ -485,37 +912,28 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 
 int ieee80211_hw_config(struct ieee80211_local *local)
 {
-       struct ieee80211_hw_mode *mode;
        struct ieee80211_channel *chan;
        int ret = 0;
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning)
                chan = local->scan_channel;
-               mode = local->scan_hw_mode;
-       } else {
+       else
                chan = local->oper_channel;
-               mode = local->oper_hw_mode;
-       }
 
-       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);
-       }
-       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;
+       local->hw.conf.channel = chan;
+
+       if (!local->hw.conf.power_level)
+               local->hw.conf.power_level = chan->max_power;
+       else
+               local->hw.conf.power_level = min(chan->max_power,
+                                              local->hw.conf.power_level);
+
+       local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
 
 #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 */
+       printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+              wiphy_name(local->hw.wiphy), chan->center_freq);
+#endif
 
        if (local->open_count)
                ret = local->ops->config(local_to_hw(local), &local->hw.conf);
@@ -523,25 +941,81 @@ int ieee80211_hw_config(struct ieee80211_local *local)
        return ret;
 }
 
-void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes)
+/**
+ * ieee80211_hw_config_ht should be used only after legacy configuration
+ * has been determined, as ht configuration depends upon the hardware's
+ * HT abilities for a _specific_ band.
+ */
+int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
+                          struct ieee80211_ht_info *req_ht_cap,
+                          struct ieee80211_ht_bss_info *req_bss_cap)
 {
-       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));
+       struct ieee80211_conf *conf = &local->hw.conf;
+       struct ieee80211_supported_band *sband;
+       int i;
+
+       sband = local->hw.wiphy->bands[conf->channel->band];
+
+       /* HT is not supported */
+       if (!sband->ht_info.ht_supported) {
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+               return -EOPNOTSUPP;
+       }
+
+       /* disable HT */
+       if (!enable_ht) {
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+       } else {
+               conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+               conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+               conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+               conf->ht_conf.cap |=
+                       sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+               conf->ht_bss_conf.primary_channel =
+                       req_bss_cap->primary_channel;
+               conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+               conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+               for (i = 0; i < SUPP_MCS_SET_LEN; i++)
+                       conf->ht_conf.supp_mcs_set[i] =
+                               sband->ht_info.supp_mcs_set[i] &
+                                 req_ht_cap->supp_mcs_set[i];
+
+               /* In STA mode, this gives us indication
+                * to the AP's mode of operation */
+               conf->ht_conf.ht_supported = 1;
+               conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+               conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+       }
+
+       local->ops->conf_ht(local_to_hw(local), &local->hw.conf);
+
+       return 0;
+}
+
+void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+                                     u32 changed)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       if (!changed)
+               return;
+
+       if (local->ops->bss_info_changed)
+               local->ops->bss_info_changed(local_to_hw(local),
+                                            &sdata->vif,
+                                            &sdata->bss_conf,
+                                            changed);
 }
 
 void ieee80211_reset_erp_info(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION |
-                       IEEE80211_SDATA_SHORT_PREAMBLE);
-       ieee80211_erp_info_change_notify(dev,
-                                        IEEE80211_ERP_CHANGE_PROTECTION |
-                                        IEEE80211_ERP_CHANGE_PREAMBLE);
+       sdata->bss_conf.use_cts_prot = 0;
+       sdata->bss_conf.use_short_preamble = 0;
+       ieee80211_bss_info_change_notify(sdata,
+                                        BSS_CHANGED_ERP_CTS_PROT |
+                                        BSS_CHANGED_ERP_PREAMBLE);
 }
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -591,6 +1065,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
        struct sk_buff *skb;
        struct ieee80211_rx_status rx_status;
        struct ieee80211_tx_status *tx_status;
+       struct ieee80211_ra_tid *ra_tid;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -598,7 +1073,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
                case IEEE80211_RX_MSG:
                        /* status is in skb->cb */
                        memcpy(&rx_status, skb->cb, sizeof(rx_status));
-                       /* Clear skb->type in order to not confuse kernel
+                       /* Clear skb->pkt_type in order to not confuse kernel
                         * netstack. */
                        skb->pkt_type = 0;
                        __ieee80211_rx(local_to_hw(local), skb, &rx_status);
@@ -611,6 +1086,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
                                            skb, tx_status);
                        kfree(tx_status);
                        break;
+               case IEEE80211_DELBA_MSG:
+                       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+                       ieee80211_stop_tx_ba_cb(local_to_hw(local),
+                                               ra_tid->ra, ra_tid->tid);
+                       dev_kfree_skb(skb);
+                       break;
+               case IEEE80211_ADDBA_MSG:
+                       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+                       ieee80211_start_tx_ba_cb(local_to_hw(local),
+                                                ra_tid->ra, ra_tid->tid);
+                       dev_kfree_skb(skb);
+                       break ;
                default: /* should never get here! */
                        printk(KERN_ERR "%s: Unknown message type (%d)\n",
                               wiphy_name(local->hw.wiphy), skb->pkt_type);
@@ -633,7 +1120,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
        struct ieee80211_tx_packet_data *pkt_data;
 
        pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       pkt_data->ifindex = control->ifindex;
+       pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
        pkt_data->flags = 0;
        if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
                pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
@@ -641,6 +1128,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
        if (control->flags & IEEE80211_TXCTL_REQUEUE)
                pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+       if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
+               pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
        pkt_data->queue = control->queue;
 
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -695,7 +1184,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
        u16 frag, type;
        struct ieee80211_tx_status_rtap_hdr *rthdr;
        struct ieee80211_sub_if_data *sdata;
-       int monitors;
+       struct net_device *prev_dev = NULL;
 
        if (!status) {
                printk(KERN_ERR
@@ -768,10 +1257,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                        sta_info_put(sta);
                        return;
                }
-       } else {
-               /* FIXME: STUPID to call this with both local and local->mdev */
-               rate_control_tx_status(local, local->mdev, skb, status);
-       }
+       } else
+               rate_control_tx_status(local->mdev, skb, status);
 
        ieee80211_led_tx(local, 0);
 
@@ -810,7 +1297,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
        /* this was a transmitted frame, but now we want to reuse it */
        skb_orphan(skb);
 
-       if (!local->monitors) {
+       /*
+        * This is a bit racy but we can avoid a lot of work
+        * with this test...
+        */
+       if (!local->monitors && !local->cooked_mntrs) {
                dev_kfree_skb(skb);
                return;
        }
@@ -844,42 +1335,37 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        rthdr->data_retries = status->retry_count;
 
+       /* 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));
+
        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;
-
-               if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+               if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
                        if (!netif_running(sdata->dev))
                                continue;
-                       monitors--;
-                       if (monitors)
+
+                       if (prev_dev) {
                                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;
+                               if (skb2) {
+                                       skb2->dev = prev_dev;
+                                       netif_rx(skb2);
+                               }
+                       }
+
+                       prev_dev = sdata->dev;
                }
        }
- out:
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+               skb = NULL;
+       }
        rcu_read_unlock();
-       if (skb)
-               dev_kfree_skb(skb);
+       dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
 
@@ -949,9 +1435,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->hw.queues = 1; /* default */
 
        local->mdev = mdev;
-       local->rx_pre_handlers = ieee80211_rx_pre_handlers;
-       local->rx_handlers = ieee80211_rx_handlers;
-       local->tx_handlers = ieee80211_tx_handlers;
 
        local->bridge_packets = 1;
 
@@ -961,10 +1444,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->long_retry_limit = 4;
        local->hw.conf.radio_enabled = 1;
 
-       local->enabled_modes = ~0;
-
-       INIT_LIST_HEAD(&local->modes_list);
-
        INIT_LIST_HEAD(&local->interfaces);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
@@ -976,10 +1455,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        mdev->open = ieee80211_master_open;
        mdev->stop = ieee80211_master_stop;
        mdev->type = ARPHRD_IEEE80211;
-       mdev->hard_header_parse = header_parse_80211;
+       mdev->header_ops = &ieee80211_header_ops;
        mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-       sdata->type = IEEE80211_IF_TYPE_AP;
+       sdata->vif.type = IEEE80211_IF_TYPE_AP;
        sdata->dev = mdev;
        sdata->local = local;
        sdata->u.ap.force_unicast_rateidx = -1;
@@ -1009,6 +1488,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        struct ieee80211_local *local = hw_to_local(hw);
        const char *name;
        int result;
+       enum ieee80211_band band;
+
+       /*
+        * generic code guarantees at least one band,
+        * set this very early because much code assumes
+        * that hw.conf.channel is assigned
+        */
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               struct ieee80211_supported_band *sband;
+
+               sband = local->hw.wiphy->bands[band];
+               if (sband) {
+                       /* init channel we're on */
+                       local->hw.conf.channel =
+                       local->oper_channel =
+                       local->scan_channel = &sband->channels[0];
+                       break;
+               }
+       }
 
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
@@ -1061,7 +1559,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        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);
+       result = ieee80211_init_rate_ctrl_alg(local,
+                                             hw->rate_control_algorithm);
        if (result < 0) {
                printk(KERN_DEBUG "%s: Failed to initialize rate control "
                       "algorithm\n", wiphy_name(local->hw.wiphy));
@@ -1109,44 +1608,10 @@ fail_workqueue:
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
 
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
-                             struct ieee80211_hw_mode *mode)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_rate *rate;
-       int i;
-
-       INIT_LIST_HEAD(&mode->list);
-       list_add_tail(&mode->list, &local->modes_list);
-
-       local->hw_modes |= (1 << mode->mode);
-       for (i = 0; i < mode->num_rates; i++) {
-               rate = &(mode->rates[i]);
-               rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
-       }
-       ieee80211_prepare_rates(local, mode);
-
-       if (!local->oper_hw_mode) {
-               /* Default to this mode */
-               local->hw.conf.phymode = mode->mode;
-               local->oper_hw_mode = local->scan_hw_mode = mode;
-               local->oper_channel = local->scan_channel = &mode->channels[0];
-               local->hw.conf.mode = local->oper_hw_mode;
-               local->hw.conf.chan = local->oper_channel;
-       }
-
-       if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
-               ieee80211_set_default_regdomain(mode);
-
-       return 0;
-}
-EXPORT_SYMBOL(ieee80211_register_hwmode);
-
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata, *tmp;
-       int i;
 
        tasklet_kill(&local->tx_pending_tasklet);
        tasklet_kill(&local->tasklet);
@@ -1187,11 +1652,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        rate_control_deinitialize(local);
        debugfs_hw_del(local);
 
-       for (i = 0; i < NUM_IEEE80211_MODES; i++) {
-               kfree(local->supp_rates[i]);
-               kfree(local->basic_rates[i]);
-       }
-
        if (skb_queue_len(&local->skb_queue)
                        || skb_queue_len(&local->skb_queue_unreliable))
                printk(KERN_WARNING "%s: skb_queue not empty\n",
@@ -1222,21 +1682,38 @@ static int __init ieee80211_init(void)
 
        BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
 
+       ret = rc80211_simple_init();
+       if (ret)
+               goto out;
+
+       ret = rc80211_pid_init();
+       if (ret)
+               goto out_cleanup_simple;
+
        ret = ieee80211_wme_register();
        if (ret) {
                printk(KERN_DEBUG "ieee80211_init: failed to "
                       "initialize WME (err=%d)\n", ret);
-               return ret;
+               goto out_cleanup_pid;
        }
 
        ieee80211_debugfs_netdev_init();
-       ieee80211_regdomain_init();
 
        return 0;
+
+ out_cleanup_pid:
+       rc80211_pid_exit();
+ out_cleanup_simple:
+       rc80211_simple_exit();
+ out:
+       return ret;
 }
 
 static void __exit ieee80211_exit(void)
 {
+       rc80211_simple_exit();
+       rc80211_pid_exit();
+
        ieee80211_wme_unregister();
        ieee80211_debugfs_netdev_exit();
 }
diff --git a/package/mac80211/src/net/mac80211/ieee80211_common.h b/package/mac80211/src/net/mac80211/ieee80211_common.h
deleted file mode 100644 (file)
index c15295d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * IEEE 802.11 driver (80211.o) -- hostapd interface
- * Copyright 2002-2004, Instant802 Networks, 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 IEEE80211_COMMON_H
-#define IEEE80211_COMMON_H
-
-#include <linux/types.h>
-
-/*
- * This is common header information with user space. It is used on all
- * frames sent to wlan#ap interface.
- */
-
-#define IEEE80211_FI_VERSION 0x80211001
-
-struct ieee80211_frame_info {
-       __be32 version;
-       __be32 length;
-       __be64 mactime;
-       __be64 hosttime;
-       __be32 phytype;
-       __be32 channel;
-       __be32 datarate;
-       __be32 antenna;
-       __be32 priority;
-       __be32 ssi_type;
-       __be32 ssi_signal;
-       __be32 ssi_noise;
-       __be32 preamble;
-       __be32 encoding;
-
-       /* Note: this structure is otherwise identical to capture format used
-        * in linux-wlan-ng, but this additional field is used to provide meta
-        * data about the frame to hostapd. This was the easiest method for
-        * providing this information, but this might change in the future. */
-       __be32 msg_type;
-} __attribute__ ((packed));
-
-
-enum ieee80211_msg_type {
-       ieee80211_msg_normal = 0,
-       ieee80211_msg_tx_callback_ack = 1,
-       ieee80211_msg_tx_callback_fail = 2,
-       /* 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,
-       /* 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 {
-       int tx_rx_count;
-       char ifname[IFNAMSIZ];
-       u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */
-};
-
-
-enum ieee80211_phytype {
-       ieee80211_phytype_fhss_dot11_97  = 1,
-       ieee80211_phytype_dsss_dot11_97  = 2,
-       ieee80211_phytype_irbaseband     = 3,
-       ieee80211_phytype_dsss_dot11_b   = 4,
-       ieee80211_phytype_pbcc_dot11_b   = 5,
-       ieee80211_phytype_ofdm_dot11_g   = 6,
-       ieee80211_phytype_pbcc_dot11_g   = 7,
-       ieee80211_phytype_ofdm_dot11_a   = 8,
-};
-
-enum ieee80211_ssi_type {
-       ieee80211_ssi_none = 0,
-       ieee80211_ssi_norm = 1, /* normalized, 0-1000 */
-       ieee80211_ssi_dbm = 2,
-       ieee80211_ssi_raw = 3, /* raw SSI */
-};
-
-struct ieee80211_radar_info {
-               int channel;
-               int radar;
-               int radar_type;
-};
-
-#endif /* IEEE80211_COMMON_H */
index d34a9deca67ad25bc36c44c3422dae6128548e42..1b4a4497030d8100650db3464fdd9525053ed80d 100644 (file)
@@ -37,8 +37,6 @@
 
 struct ieee80211_local;
 
-#define BIT(x) (1 << (x))
-
 #define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
 
 /* Maximum number of broadcast/multicast frames to buffer when some of the
@@ -81,8 +79,7 @@ struct ieee80211_sta_bss {
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        size_t ssid_len;
        u16 capability; /* host byte order */
-       int hw_mode;
-       int channel;
+       enum ieee80211_band band;
        int freq;
        int rssi, signal, noise;
        u8 *wpa_ie;
@@ -91,6 +88,8 @@ 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;
@@ -109,9 +108,17 @@ struct ieee80211_sta_bss {
 };
 
 
-typedef enum {
-       TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
-} ieee80211_txrx_result;
+typedef unsigned __bitwise__ ieee80211_tx_result;
+#define TX_CONTINUE    ((__force ieee80211_tx_result) 0u)
+#define TX_DROP                ((__force ieee80211_tx_result) 1u)
+#define TX_QUEUED      ((__force ieee80211_tx_result) 2u)
+
+typedef unsigned __bitwise__ ieee80211_rx_result;
+#define RX_CONTINUE            ((__force ieee80211_rx_result) 0u)
+#define RX_DROP_UNUSABLE       ((__force ieee80211_rx_result) 1u)
+#define RX_DROP_MONITOR                ((__force ieee80211_rx_result) 2u)
+#define RX_QUEUED              ((__force ieee80211_rx_result) 3u)
+
 
 /* flags used in struct ieee80211_txrx_data.flags */
 /* whether the MSDU was fragmented */
@@ -123,6 +130,8 @@ typedef enum {
 /* frame is destined to interface currently processed (incl. multicast frames) */
 #define IEEE80211_TXRXD_RXRA_MATCH             BIT(5)
 #define IEEE80211_TXRXD_TX_INJECTED            BIT(6)
+#define IEEE80211_TXRXD_RX_AMSDU               BIT(7)
+#define IEEE80211_TXRXD_RX_CMNTR_REPORTED      BIT(8)
 struct ieee80211_txrx_data {
        struct sk_buff *skb;
        struct net_device *dev;
@@ -135,13 +144,12 @@ struct ieee80211_txrx_data {
        union {
                struct {
                        struct ieee80211_tx_control *control;
-                       struct ieee80211_hw_mode *mode;
+                       struct ieee80211_channel *channel;
                        struct ieee80211_rate *rate;
                        /* use this rate (if set) for last fragment; rate can
                         * be set to lower rate for the first fragments, e.g.,
                         * when using CTS protection with IEEE 802.11g. */
                        struct ieee80211_rate *last_frag_rate;
-                       int last_frag_hwrate;
 
                        /* Extra fragments (in addition to the first fragment
                         * in skb) */
@@ -150,6 +158,7 @@ struct ieee80211_txrx_data {
                } tx;
                struct {
                        struct ieee80211_rx_status *status;
+                       struct ieee80211_rate *rate;
                        int sent_ps_buffered;
                        int queue;
                        int load;
@@ -163,6 +172,8 @@ struct ieee80211_txrx_data {
 #define IEEE80211_TXPD_REQ_TX_STATUS   BIT(0)
 #define IEEE80211_TXPD_DO_NOT_ENCRYPT  BIT(1)
 #define IEEE80211_TXPD_REQUEUE         BIT(2)
+#define IEEE80211_TXPD_EAPOL_FRAME     BIT(3)
+#define IEEE80211_TXPD_AMPDU           BIT(4)
 /* Stored in sk_buff->cb */
 struct ieee80211_tx_packet_data {
        int ifindex;
@@ -176,21 +187,18 @@ struct ieee80211_tx_stored_packet {
        struct sk_buff *skb;
        int num_extra_frag;
        struct sk_buff **extra_frag;
-       int last_frag_rateidx;
-       int last_frag_hwrate;
        struct ieee80211_rate *last_frag_rate;
        unsigned int last_frag_rate_ctrl_probe;
 };
 
-typedef ieee80211_txrx_result (*ieee80211_tx_handler)
-(struct ieee80211_txrx_data *tx);
-
-typedef ieee80211_txrx_result (*ieee80211_rx_handler)
-(struct ieee80211_txrx_data *rx);
+struct beacon_data {
+       u8 *head, *tail;
+       int head_len, tail_len;
+       int dtim_period;
+};
 
 struct ieee80211_if_ap {
-       u8 *beacon_head, *beacon_tail;
-       int beacon_head_len, beacon_tail_len;
+       struct beacon_data *beacon;
 
        struct list_head vlans;
 
@@ -203,7 +211,7 @@ struct ieee80211_if_ap {
        u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
        atomic_t num_sta_ps; /* number of stations in PS mode */
        struct sk_buff_head ps_bc_buf;
-       int dtim_period, dtim_count;
+       int dtim_count;
        int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
        int max_ratectrl_rateidx; /* max TX rateidx for rate control */
        int num_beacons; /* number of TXed beacon frames for this BSS */
@@ -232,6 +240,7 @@ struct ieee80211_if_vlan {
 #define IEEE80211_STA_AUTO_SSID_SEL    BIT(10)
 #define IEEE80211_STA_AUTO_BSSID_SEL   BIT(11)
 #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
+#define IEEE80211_STA_PRIVACY_INVOKED  BIT(13)
 struct ieee80211_if_sta {
        enum {
                IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
@@ -243,6 +252,8 @@ struct ieee80211_if_sta {
        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        size_t ssid_len;
+       u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
+       size_t scan_ssid_len;
        u16 aid;
        u16 ap_capab, capab;
        u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -261,7 +272,6 @@ struct ieee80211_if_sta {
        unsigned long request;
        struct sk_buff_head skb_queue;
 
-       int key_management_enabled;
        unsigned long last_probe;
 
 #define IEEE80211_AUTH_ALG_OPEN BIT(0)
@@ -273,7 +283,7 @@ struct ieee80211_if_sta {
 
        unsigned long ibss_join_req;
        struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
-       u32 supp_rates_bits;
+       u32 supp_rates_bits[IEEE80211_NUM_BANDS];
 
        int wmm_last_param_set;
 };
@@ -282,15 +292,10 @@ struct ieee80211_if_sta {
 /* 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)
+#define IEEE80211_SDATA_USERSPACE_MLME BIT(2)
+#define IEEE80211_SDATA_OPERATING_GMODE        BIT(3)
 struct ieee80211_sub_if_data {
        struct list_head list;
-       enum ieee80211_if_types type;
 
        struct wireless_dev wdev;
 
@@ -303,11 +308,11 @@ struct ieee80211_sub_if_data {
        unsigned int flags;
 
        int drop_unencrypted;
-       int eapol; /* 0 = process EAPOL frames as normal data frames,
-                   * 1 = send EAPOL frames through wlan#ap to hostapd
-                   *     (default) */
-       int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
-                        * port */
+
+       /*
+        * basic rates of this AP or the AP we're associated to
+        */
+       u64 basic_rates;
 
        u16 sequence;
 
@@ -319,6 +324,15 @@ struct ieee80211_sub_if_data {
        struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
        struct ieee80211_key *default_key;
 
+       /*
+        * BSS configuration for this interface.
+        *
+        * FIXME: I feel bad putting this here when we already have a
+        *        bss pointer, but the bss pointer is just wrong when
+        *        you have multiple virtual STA mode interfaces...
+        *        This needs to be fixed.
+        */
+       struct ieee80211_bss_conf bss_conf;
        struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
 
        union {
@@ -326,6 +340,7 @@ struct ieee80211_sub_if_data {
                struct ieee80211_if_wds wds;
                struct ieee80211_if_vlan vlan;
                struct ieee80211_if_sta sta;
+               u32 mntr_flags;
        } u;
        int channel_use;
        int channel_use_raw;
@@ -336,8 +351,6 @@ struct ieee80211_sub_if_data {
                struct {
                        struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
-                       struct dentry *eapol;
-                       struct dentry *ieee8021_x;
                        struct dentry *state;
                        struct dentry *bssid;
                        struct dentry *prev_bssid;
@@ -356,30 +369,21 @@ struct ieee80211_sub_if_data {
                struct {
                        struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
-                       struct dentry *eapol;
-                       struct dentry *ieee8021_x;
                        struct dentry *num_sta_ps;
-                       struct dentry *dtim_period;
                        struct dentry *dtim_count;
                        struct dentry *num_beacons;
                        struct dentry *force_unicast_rateidx;
                        struct dentry *max_ratectrl_rateidx;
                        struct dentry *num_buffered_multicast;
-                       struct dentry *beacon_head_len;
-                       struct dentry *beacon_tail_len;
                } ap;
                struct {
                        struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
-                       struct dentry *eapol;
-                       struct dentry *ieee8021_x;
                        struct dentry *peer;
                } wds;
                struct {
                        struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
-                       struct dentry *eapol;
-                       struct dentry *ieee8021_x;
                } vlan;
                struct {
                        struct dentry *mode;
@@ -387,13 +391,23 @@ struct ieee80211_sub_if_data {
                struct dentry *default_key;
        } debugfs;
 #endif
+       /* must be last, dynamically sized area in this! */
+       struct ieee80211_vif vif;
 };
 
+static inline
+struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
+{
+       return container_of(p, struct ieee80211_sub_if_data, vif);
+}
+
 #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
 
 enum {
        IEEE80211_RX_MSG        = 1,
        IEEE80211_TX_STATUS_MSG = 2,
+       IEEE80211_DELBA_MSG     = 3,
+       IEEE80211_ADDBA_MSG     = 4,
 };
 
 struct ieee80211_local {
@@ -404,12 +418,11 @@ struct ieee80211_local {
 
        const struct ieee80211_ops *ops;
 
-       /* List of registered struct ieee80211_hw_mode */
-       struct list_head modes_list;
-
        struct net_device *mdev; /* wmaster# - "master" 802.11 device */
        int open_count;
-       int monitors;
+       int monitors, cooked_mntrs;
+       /* number of interfaces with corresponding FIF_ flags */
+       int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
        unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
        u8 wstats_flags;
@@ -437,8 +450,8 @@ struct ieee80211_local {
        struct sta_info *sta_hash[STA_HASH_SIZE];
        struct timer_list sta_cleanup;
 
-       unsigned long state[NUM_TX_DATA_QUEUES];
-       struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+       unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
+       struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
        struct tasklet_struct tx_pending_tasklet;
 
        /* number of interfaces with corresponding IFF_ flags */
@@ -446,11 +459,6 @@ struct ieee80211_local {
 
        struct rate_control_ref *rate_ctrl;
 
-       /* 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 fragmentation_threshold;
        int short_retry_limit; /* dot11ShortRetryLimit */
@@ -464,29 +472,23 @@ struct ieee80211_local {
                             * deliver multicast frames both back to wireless
                             * media and to the local net stack */
 
-       ieee80211_rx_handler *rx_pre_handlers;
-       ieee80211_rx_handler *rx_handlers;
-       ieee80211_tx_handler *tx_handlers;
-
        struct list_head interfaces;
 
-       int sta_scanning;
+       bool sta_sw_scanning;
+       bool sta_hw_scanning;
        int scan_channel_idx;
+       enum ieee80211_band scan_band;
+
        enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
        unsigned long last_scan_completed;
        struct delayed_work scan_work;
        struct net_device *scan_dev;
        struct ieee80211_channel *oper_channel, *scan_channel;
-       struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
        u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
        size_t scan_ssid_len;
        struct list_head sta_bss_list;
        struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
        spinlock_t sta_bss_lock;
-#define IEEE80211_SCAN_MATCH_SSID BIT(0)
-#define IEEE80211_SCAN_WPA_ONLY BIT(1)
-#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
-       int scan_flags;
 
        /* SNMP counters */
        /* dot11CountersTable */
@@ -503,8 +505,9 @@ struct ieee80211_local {
 
 #ifdef CONFIG_MAC80211_LEDS
        int tx_led_counter, rx_led_counter;
-       struct led_trigger *tx_led, *rx_led, *assoc_led;
-       char tx_led_name[32], rx_led_name[32], assoc_led_name[32];
+       struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
+       char tx_led_name[32], rx_led_name[32],
+            assoc_led_name[32], radio_led_name[32];
 #endif
 
        u32 channel_use;
@@ -549,14 +552,8 @@ struct ieee80211_local {
        int wifi_wme_noack_test;
        unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
-       unsigned int enabled_modes; /* bitfield of allowed modes;
-                                     * (1 << MODE_*) */
-       unsigned int hw_modes; /* bitfield of supported hardware modes;
-                               * (1 << MODE_*) */
-
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct local_debugfsdentries {
-               struct dentry *channel;
                struct dentry *frequency;
                struct dentry *antenna_sel_tx;
                struct dentry *antenna_sel_rx;
@@ -566,9 +563,7 @@ struct ieee80211_local {
                struct dentry *short_retry_limit;
                struct dentry *long_retry_limit;
                struct dentry *total_ps_buffered;
-               struct dentry *mode;
                struct dentry *wep_iv;
-               struct dentry *modes;
                struct dentry *statistics;
                struct local_debugfsdentries_statsdentries {
                        struct dentry *transmitted_fragment_count;
@@ -616,6 +611,12 @@ struct ieee80211_local {
 #endif
 };
 
+/* this struct represents 802.11n's RA/TID combination */
+struct ieee80211_ra_tid {
+       u8 ra[ETH_ALEN];
+       u16 tid;
+};
+
 static inline struct ieee80211_local *hw_to_local(
        struct ieee80211_hw *hw)
 {
@@ -673,23 +674,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local,
        read_unlock_bh(&local->sta_lock);
 }
 
-/**
- * ieee80211_is_erp_rate - Check if a rate is an ERP rate
- * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
- * @rate: Transmission rate to check, in 100 kbps
- *
- * Check if a given rate is an Extended Rate PHY (ERP) rate.
- */
-static inline int ieee80211_is_erp_rate(int phymode, int rate)
-{
-       if (phymode == MODE_IEEE80211G) {
-               if (rate != 10 && rate != 20 &&
-                   rate != 55 && rate != 110)
-                       return 1;
-       }
-       return 0;
-}
-
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
        return compare_ether_addr(raddr, addr) == 0 ||
@@ -701,13 +685,12 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 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);
-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);
-struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
-                                         int phymode, int hwrate);
+int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
+                          struct ieee80211_ht_info *req_ht_cap,
+                          struct ieee80211_ht_bss_info *req_bss_cap);
 
 /* ieee80211_ioctl.c */
 extern const struct iw_handler_def ieee80211_iw_handler_def;
@@ -735,7 +718,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
 /* ieee80211_ioctl.c */
 int ieee80211_set_compression(struct ieee80211_local *local,
                              struct net_device *dev, struct sta_info *sta);
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+int ieee80211_set_freq(struct ieee80211_local *local, int freq);
 /* ieee80211_sta.c */
 void ieee80211_sta_timer(unsigned long data);
 void ieee80211_sta_work(struct work_struct *work);
@@ -749,8 +732,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
                            struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status);
+ieee80211_rx_result ieee80211_sta_rx_scan(
+       struct net_device *dev, struct sk_buff *skb,
+       struct ieee80211_rx_status *rx_status);
 void ieee80211_rx_bss_list_init(struct net_device *dev);
 void ieee80211_rx_bss_list_deinit(struct net_device *dev);
 int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
@@ -759,9 +743,23 @@ 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_erp_info_change_notify(struct net_device *dev, u8 changes);
+void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+                                     u32 changed);
 void ieee80211_reset_erp_info(struct net_device *dev);
-
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+                                  struct ieee80211_ht_info *ht_info);
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                       struct ieee80211_ht_addt_info *ht_add_info_ie,
+                       struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+                                 u16 tid, u8 dialog_token, u16 start_seq_num,
+                                 u16 agg_size, u16 timeout);
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+                               u16 initiator, u16 reason_code);
+void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
+                               u16 tid, u16 initiator, u16 reason);
+void sta_rx_agg_session_timer_expired(unsigned long data);
+void sta_addba_resp_timer_expired(unsigned long data);
 /* ieee80211_iface.c */
 int ieee80211_if_add(struct net_device *dev, const char *name,
                     struct net_device **new_dev, int type);
@@ -773,16 +771,7 @@ 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);
 
-/* regdomain.c */
-void ieee80211_regdomain_init(void);
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
-
-/* 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);
@@ -793,8 +782,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 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);
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+                       enum ieee80211_if_types type);
 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,
index 43e505d294527ca1769c24da69b82c7b42ee6e66..f66f1ddc3fda0d11200548350cd286b48593ff42 100644 (file)
@@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
 
        /* Default values for sub-interface parameters */
        sdata->drop_unencrypted = 0;
-       sdata->eapol = 1;
        for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
                skb_queue_head_init(&sdata->fragments[i].skb_list);
 
@@ -48,7 +47,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
        int ret;
 
        ASSERT_RTNL();
-       ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+       ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
                            name, ieee80211_if_setup);
        if (!ndev)
                return -ENOMEM;
@@ -67,7 +66,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
        sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
        ndev->ieee80211_ptr = &sdata->wdev;
        sdata->wdev.wiphy = local->hw.wiphy;
-       sdata->type = IEEE80211_IF_TYPE_AP;
+       sdata->vif.type = IEEE80211_IF_TYPE_AP;
        sdata->dev = ndev;
        sdata->local = local;
        ieee80211_if_sdata_init(sdata);
@@ -99,7 +98,7 @@ fail:
 void ieee80211_if_set_type(struct net_device *dev, int type)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       int oldtype = sdata->type;
+       int oldtype = sdata->vif.type;
 
        /*
         * We need to call this function on the master interface
@@ -117,7 +116,9 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 
        /* most have no BSS pointer */
        sdata->bss = NULL;
-       sdata->type = type;
+       sdata->vif.type = type;
+
+       sdata->basic_rates = 0;
 
        switch (type) {
        case IEEE80211_IF_TYPE_WDS:
@@ -127,7 +128,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
                sdata->u.vlan.ap = NULL;
                break;
        case IEEE80211_IF_TYPE_AP:
-               sdata->u.ap.dtim_period = 2;
                sdata->u.ap.force_unicast_rateidx = -1;
                sdata->u.ap.max_ratectrl_rateidx = -1;
                skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -160,6 +160,8 @@ 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;
+               sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+                                     MONITOR_FLAG_OTHER_BSS;
                break;
        default:
                printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
@@ -182,7 +184,7 @@ void ieee80211_if_reinit(struct net_device *dev)
 
        ieee80211_if_sdata_deinit(sdata);
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_INVALID:
                /* cannot happen */
                WARN_ON(1);
@@ -208,8 +210,7 @@ void ieee80211_if_reinit(struct net_device *dev)
                        }
                }
 
-               kfree(sdata->u.ap.beacon_head);
-               kfree(sdata->u.ap.beacon_tail);
+               kfree(sdata->u.ap.beacon);
 
                while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
                        local->total_ps_buffered--;
@@ -280,7 +281,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
        ASSERT_RTNL();
 
        list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
-               if ((sdata->type == id || id == -1) &&
+               if ((sdata->vif.type == id || id == -1) &&
                    strcmp(name, sdata->dev->name) == 0 &&
                    sdata->dev != local->mdev) {
                        list_del_rcu(&sdata->list);
index f95d488726b59cc06cebaf88b4b97fbaf9908e47..54ad07aafe2d4de3a1a53eaa3f1348a928a21765 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "ieee80211_led.h"
 #include "ieee80211_rate.h"
 #include "wpa.h"
 #include "aes_ccm.h"
@@ -64,9 +65,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
                sta = sta_info_get(local, sta_addr);
                if (!sta) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       DECLARE_MAC_BUF(mac);
                        printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
-                              MAC_FMT "\n",
-                              dev->name, MAC_ARG(sta_addr));
+                              "%s\n",
+                              dev->name, print_mac(mac, sta_addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
                        return -ENOENT;
@@ -110,8 +112,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
        if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
                return -EOPNOTSUPP;
 
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
                if (ret)
                        return ret;
@@ -127,22 +129,7 @@ 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;
-       default:
-               strcpy(name, "IEEE 802.11");
-               break;
-       }
+       strcpy(name, "IEEE 802.11");
 
        return 0;
 }
@@ -154,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct iw_range *range = (struct iw_range *) extra;
-       struct ieee80211_hw_mode *mode = NULL;
+       enum ieee80211_band band;
        int c = 0;
 
        data->length = sizeof(struct iw_range);
@@ -189,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
        range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
                          IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-       list_for_each_entry(mode, &local->modes_list, list) {
-               int i = 0;
 
-               if (!(local->enabled_modes & (1 << mode->mode)) ||
-                   (local->hw_modes & local->enabled_modes &
-                    (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+       for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+               int i;
+               struct ieee80211_supported_band *sband;
+
+               sband = local->hw.wiphy->bands[band];
+
+               if (!sband)
                        continue;
 
-               while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
-                       struct ieee80211_channel *chan = &mode->channels[i];
+               for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
+                       struct ieee80211_channel *chan = &sband->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;
+                       if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
+                               range->freq[c].i =
+                                       ieee80211_frequency_to_channel(
+                                               chan->center_freq);
+                               range->freq[c].m = chan->center_freq;
+                               range->freq[c].e = 6;
                                c++;
                        }
-                       i++;
                }
        }
        range->num_channels = c;
@@ -217,6 +207,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
        IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
        IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 
+       range->scan_capa |= IW_SCAN_CAPA_ESSID;
+
        return 0;
 }
 
@@ -228,7 +220,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int type;
 
-       if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
                return -EOPNOTSUPP;
 
        switch (*mode) {
@@ -245,7 +237,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
                return -EINVAL;
        }
 
-       if (type == sdata->type)
+       if (type == sdata->vif.type)
                return 0;
        if (netif_running(dev))
                return -EBUSY;
@@ -264,7 +256,7 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_AP:
                *mode = IW_MODE_MASTER;
                break;
@@ -290,28 +282,38 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
        return 0;
 }
 
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
 {
-       struct ieee80211_hw_mode *mode;
-       int c, set = 0;
+       int set = 0;
        int ret = -EINVAL;
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       int i;
 
-       list_for_each_entry(mode, &local->modes_list, list) {
-               if (!(local->enabled_modes & (1 << mode->mode)))
+       for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+               sband = local->hw.wiphy->bands[band];
+
+               if (!sband)
                        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))) {
+
+               for (i = 0; i < sband->n_channels; i++) {
+                       struct ieee80211_channel *chan = &sband->channels[i];
+
+                       if (chan->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       if (chan->center_freq == freqMHz) {
+                               set = 1;
                                local->oper_channel = chan;
-                               local->oper_hw_mode = mode;
-                               set++;
+                               break;
                        }
                }
+               if (set)
+                       break;
        }
 
        if (set) {
-               if (local->sta_scanning)
+               if (local->sta_sw_scanning)
                        ret = 0;
                else
                        ret = ieee80211_hw_config(local);
@@ -329,24 +331,25 @@ static int ieee80211_ioctl_siwfreq(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);
 
-       if (sdata->type == IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
                sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
        /* 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)
+                       if (sdata->vif.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);
+                       return ieee80211_set_freq(local,
+                               ieee80211_channel_to_frequency(freq->m));
        } 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);
+                       return ieee80211_set_freq(local, freq->m / div);
                else
                        return -EINVAL;
        }
@@ -359,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
 {
        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->m = local->hw.conf.channel->center_freq;
        freq->e = 6;
 
        return 0;
@@ -381,8 +381,8 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                len--;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                int ret;
                if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
                        if (len > IEEE80211_MAX_SSID_LEN)
@@ -402,7 +402,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                return 0;
        }
 
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                memcpy(sdata->u.ap.ssid, ssid, len);
                memset(sdata->u.ap.ssid + len, 0,
                       IEEE80211_MAX_SSID_LEN - len);
@@ -421,8 +421,8 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
 
        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) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                int res = ieee80211_sta_get_ssid(dev, ssid, &len);
                if (res == 0) {
                        data->length = len;
@@ -432,7 +432,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
                return res;
        }
 
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                len = sdata->u.ap.ssid_len;
                if (len > IW_ESSID_MAX_SIZE)
                        len = IW_ESSID_MAX_SIZE;
@@ -452,8 +452,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
        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) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                int ret;
                if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
                        memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
@@ -472,7 +472,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
                        return ret;
                ieee80211_sta_req_auth(dev, &sdata->u.sta);
                return 0;
-       } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+       } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
                if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
                           ETH_ALEN) == 0)
                        return 0;
@@ -490,12 +490,12 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
        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) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.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) {
+       } else if (sdata->vif.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;
@@ -507,32 +507,27 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
 
 static int ieee80211_ioctl_siwscan(struct net_device *dev,
                                   struct iw_request_info *info,
-                                  struct iw_point *data, char *extra)
+                                  union iwreq_data *wrqu, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct iw_scan_req *req = NULL;
        u8 *ssid = NULL;
        size_t ssid_len = 0;
 
        if (!netif_running(dev))
                return -ENETDOWN;
 
-       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:
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+           sdata->vif.type != IEEE80211_IF_TYPE_AP)
                return -EOPNOTSUPP;
+
+       /* if SSID was specified explicitly then use that */
+       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+               req = (struct iw_scan_req *)extra;
+               ssid = req->essid;
+               ssid_len = req->essid_len;
        }
 
        return ieee80211_sta_req_scan(dev, ssid, ssid_len);
@@ -545,8 +540,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
 {
        int res;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       if (local->sta_scanning)
+
+       if (local->sta_sw_scanning || local->sta_hw_scanning)
                return -EAGAIN;
+
        res = ieee80211_sta_scan_results(dev, extra, data->length);
        if (res >= 0) {
                data->length = res;
@@ -562,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
                                  struct iw_param *rate, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       int i;
+       int i, err = -EINVAL;
        u32 target_rate = rate->value / 100000;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_supported_band *sband;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (!sdata->bss)
                return -ENODEV;
-       mode = local->oper_hw_mode;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
        /* 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 */
@@ -578,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
        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;
+
+       for (i=0; i< sband->n_bitrates; i++) {
+               struct ieee80211_rate *brate = &sband->bitrates[i];
+               int this_rate = brate->bitrate;
 
                if (target_rate == this_rate) {
                        sdata->bss->max_ratectrl_rateidx = i;
                        if (rate->fixed)
                                sdata->bss->force_unicast_rateidx = i;
+                       err = 0;
                        break;
                }
        }
-       return 0;
+       return err;
 }
 
 static int ieee80211_ioctl_giwrate(struct net_device *dev,
@@ -599,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_supported_band *sband;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_STA)
+
+       if (sdata->vif.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;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       if (sta->txrate_idx < sband->n_bitrates)
+               rate->value = sband->bitrates[sta->txrate_idx].bitrate;
        else
                rate->value = 0;
+       rate->value *= 100000;
        sta_info_put(sta);
        return 0;
 }
@@ -621,22 +628,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        bool need_reconfig = 0;
+       int new_power_level;
 
        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;
 
-       if (local->hw.conf.power_level != data->txpower.value) {
-               local->hw.conf.power_level = data->txpower.value;
+       if (data->txpower.fixed) {
+               new_power_level = data->txpower.value;
+       } else {
+               /*
+                * Automatic power level. Use maximum power for the current
+                * channel. Should be part of rate control.
+                */
+               struct ieee80211_channel* chan = local->hw.conf.channel;
+               if (!chan)
+                       return -EINVAL;
+
+               new_power_level = chan->max_power;
+       }
+
+       if (local->hw.conf.power_level != new_power_level) {
+               local->hw.conf.power_level = new_power_level;
                need_reconfig = 1;
        }
+
        if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
                local->hw.conf.radio_enabled = !(data->txpower.disabled);
                need_reconfig = 1;
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
+
        if (need_reconfig) {
                ieee80211_hw_config(local);
                /* The return value of hw_config is not of big interest here,
@@ -801,8 +824,8 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev,
        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return -EINVAL;
 
        switch (mlme->cmd) {
@@ -904,7 +927,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_param *data, char *extra)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret = 0;
 
@@ -914,32 +936,33 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
        case IW_AUTH_CIPHER_GROUP:
        case IW_AUTH_WPA_ENABLED:
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-               break;
        case IW_AUTH_KEY_MGMT:
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
+               break;
+       case IW_AUTH_DROP_UNENCRYPTED:
+               sdata->drop_unencrypted = !!data->value;
+               break;
+       case IW_AUTH_PRIVACY_INVOKED:
+               if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                        ret = -EINVAL;
                else {
+                       sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
                        /*
-                        * 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.
+                        * Privacy invoked by wpa_supplicant, store the
+                        * value and allow associating to a protected
+                        * network without having a key up front.
                         */
-                       sdata->u.sta.key_management_enabled = !!data->value;
+                       if (data->value)
+                               sdata->u.sta.flags |=
+                                       IEEE80211_STA_PRIVACY_INVOKED;
                }
                break;
        case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->type == IEEE80211_IF_TYPE_STA ||
-                   sdata->type == IEEE80211_IF_TYPE_IBSS)
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+                   sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
                        sdata->u.sta.auth_algs = data->value;
                else
                        ret = -EOPNOTSUPP;
                break;
-       case IW_AUTH_PRIVACY_INVOKED:
-               if (local->ops->set_privacy_invoked)
-                       ret = local->ops->set_privacy_invoked(
-                                       local_to_hw(local), data->value);
-               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -955,8 +978,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta = NULL;
 
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
                sta = sta_info_get(local, sdata->u.sta.bssid);
        if (!sta) {
                wstats->discard.fragment = 0;
@@ -984,8 +1007,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
 
        switch (data->flags & IW_AUTH_INDEX) {
        case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->type == IEEE80211_IF_TYPE_STA ||
-                   sdata->type == IEEE80211_IF_TYPE_IBSS)
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+                   sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
                        data->value = sdata->u.sta.auth_algs;
                else
                        ret = -EOPNOTSUPP;
index 4cf89af9d1009ffc528622d2e0f64a550c4614d4..f401484ab6d7d1502ba79051e79d3af9f2d32369 100644 (file)
@@ -43,6 +43,16 @@ void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
                led_trigger_event(local->assoc_led, LED_OFF);
 }
 
+void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
+{
+       if (unlikely(!local->radio_led))
+               return;
+       if (enabled)
+               led_trigger_event(local->radio_led, LED_FULL);
+       else
+               led_trigger_event(local->radio_led, LED_OFF);
+}
+
 void ieee80211_led_init(struct ieee80211_local *local)
 {
        local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
@@ -77,10 +87,25 @@ void ieee80211_led_init(struct ieee80211_local *local)
                        local->assoc_led = NULL;
                }
        }
+
+       local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+       if (local->radio_led) {
+               snprintf(local->radio_led_name, sizeof(local->radio_led_name),
+                        "%sradio", wiphy_name(local->hw.wiphy));
+               local->radio_led->name = local->radio_led_name;
+               if (led_trigger_register(local->radio_led)) {
+                       kfree(local->radio_led);
+                       local->radio_led = NULL;
+               }
+       }
 }
 
 void ieee80211_led_exit(struct ieee80211_local *local)
 {
+       if (local->radio_led) {
+               led_trigger_unregister(local->radio_led);
+               kfree(local->radio_led);
+       }
        if (local->assoc_led) {
                led_trigger_unregister(local->assoc_led);
                kfree(local->assoc_led);
@@ -95,6 +120,16 @@ void ieee80211_led_exit(struct ieee80211_local *local)
        }
 }
 
+char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (local->radio_led)
+               return local->radio_led_name;
+       return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
+
 char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
index 0feb22619835e0230df6e8bf9469d76e0e49f914..77b1e1ba60391120cb8eff79f57aa922466e2625 100644 (file)
@@ -16,6 +16,8 @@ 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_radio(struct ieee80211_local *local,
+                               bool enabled);
 extern void ieee80211_led_init(struct ieee80211_local *local);
 extern void ieee80211_led_exit(struct ieee80211_local *local);
 #else
@@ -29,6 +31,10 @@ static inline void ieee80211_led_assoc(struct ieee80211_local *local,
                                       bool associated)
 {
 }
+static inline void ieee80211_led_radio(struct ieee80211_local *local,
+                                      bool enabled)
+{
+}
 static inline void ieee80211_led_init(struct ieee80211_local *local)
 {
 }
index 93abb8fff1410f254c9fb6adf04ad34823bc80a5..ebe29b716b271a8124d5460750b3a5f8d1a349e0 100644 (file)
@@ -21,17 +21,35 @@ struct rate_control_alg {
 static LIST_HEAD(rate_ctrl_algs);
 static DEFINE_MUTEX(rate_ctrl_mutex);
 
+static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT;
+module_param(ieee80211_default_rc_algo, charp, 0644);
+MODULE_PARM_DESC(ieee80211_default_rc_algo,
+                "Default rate control algorithm for mac80211 to use");
+
 int ieee80211_rate_control_register(struct rate_control_ops *ops)
 {
        struct rate_control_alg *alg;
 
+       if (!ops->name)
+               return -EINVAL;
+
+       mutex_lock(&rate_ctrl_mutex);
+       list_for_each_entry(alg, &rate_ctrl_algs, list) {
+               if (!strcmp(alg->ops->name, ops->name)) {
+                       /* don't register an algorithm twice */
+                       WARN_ON(1);
+                       mutex_unlock(&rate_ctrl_mutex);
+                       return -EALREADY;
+               }
+       }
+
        alg = kzalloc(sizeof(*alg), GFP_KERNEL);
        if (alg == NULL) {
+               mutex_unlock(&rate_ctrl_mutex);
                return -ENOMEM;
        }
        alg->ops = ops;
 
-       mutex_lock(&rate_ctrl_mutex);
        list_add_tail(&alg->list, &rate_ctrl_algs);
        mutex_unlock(&rate_ctrl_mutex);
 
@@ -47,11 +65,11 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
        list_for_each_entry(alg, &rate_ctrl_algs, list) {
                if (alg->ops == ops) {
                        list_del(&alg->list);
+                       kfree(alg);
                        break;
                }
        }
        mutex_unlock(&rate_ctrl_mutex);
-       kfree(alg);
 }
 EXPORT_SYMBOL(ieee80211_rate_control_unregister);
 
@@ -61,9 +79,12 @@ ieee80211_try_rate_control_ops_get(const char *name)
        struct rate_control_alg *alg;
        struct rate_control_ops *ops = NULL;
 
+       if (!name)
+               return NULL;
+
        mutex_lock(&rate_ctrl_mutex);
        list_for_each_entry(alg, &rate_ctrl_algs, list) {
-               if (!name || !strcmp(alg->ops->name, name))
+               if (!strcmp(alg->ops->name, name))
                        if (try_module_get(alg->ops->module)) {
                                ops = alg->ops;
                                break;
@@ -73,18 +94,31 @@ ieee80211_try_rate_control_ops_get(const char *name)
        return ops;
 }
 
-/* Get the rate control algorithm. If `name' is NULL, get the first
- * available algorithm. */
+/* Get the rate control algorithm. */
 static struct rate_control_ops *
 ieee80211_rate_control_ops_get(const char *name)
 {
        struct rate_control_ops *ops;
+       const char *alg_name;
 
-       ops = ieee80211_try_rate_control_ops_get(name);
+       if (!name)
+               alg_name = ieee80211_default_rc_algo;
+       else
+               alg_name = name;
+
+       ops = ieee80211_try_rate_control_ops_get(alg_name);
        if (!ops) {
-               request_module("rc80211_%s", name ? name : "default");
-               ops = ieee80211_try_rate_control_ops_get(name);
+               request_module("rc80211_%s", alg_name);
+               ops = ieee80211_try_rate_control_ops_get(alg_name);
        }
+       if (!ops && name)
+               /* try default if specific alg requested but not found */
+               ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
+
+       /* try built-in one if specific alg requested but not found */
+       if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
+               ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+
        return ops;
 }
 
@@ -128,6 +162,38 @@ static void rate_control_release(struct kref *kref)
        kfree(ctrl_ref);
 }
 
+void rate_control_get_rate(struct net_device *dev,
+                          struct ieee80211_supported_band *sband,
+                          struct sk_buff *skb,
+                          struct rate_selection *sel)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct sta_info *sta = sta_info_get(local, hdr->addr1);
+       int i;
+
+       memset(sel, 0, sizeof(struct rate_selection));
+
+       ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+
+       /* Select a non-ERP backup rate. */
+       if (!sel->nonerp) {
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       struct ieee80211_rate *rate = &sband->bitrates[i];
+                       if (sel->rate->bitrate < rate->bitrate)
+                               break;
+
+                       if (rate_supported(sta, sband->band, i) &&
+                           !(rate->flags & IEEE80211_RATE_ERP_G))
+                               sel->nonerp = rate;
+               }
+       }
+
+       if (sta)
+               sta_info_put(sta);
+}
+
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
 {
        kref_get(&ref->kref);
@@ -178,3 +244,4 @@ void rate_control_deinitialize(struct ieee80211_local *local)
        local->rate_ctrl = NULL;
        rate_control_put(ref);
 }
+
index 7cd1ebab4f8345f4cdf008b17ecc134254c45c39..5f9a2ca49a573b0592ffbab9d6fbb0cee4dbe432 100644 (file)
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP   15
-
-
-struct rate_control_extra {
-       /* values from rate_control_get_rate() to the caller: */
-       struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
-                                      * probing */
+/* TODO: kdoc */
+struct rate_selection {
+       /* Selected transmission rate */
+       struct ieee80211_rate *rate;
+       /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
        struct ieee80211_rate *nonerp;
-
-       /* parameters from the caller to rate_control_get_rate(): */
-       struct ieee80211_hw_mode *mode;
-       u16 ethertype;
+       /* probe with this rate, or NULL for no probing */
+       struct ieee80211_rate *probe;
 };
 
-
 struct rate_control_ops {
        struct module *module;
        const char *name;
        void (*tx_status)(void *priv, struct net_device *dev,
                          struct sk_buff *skb,
                          struct ieee80211_tx_status *status);
-       struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
-                                          struct sk_buff *skb,
-                                          struct rate_control_extra *extra);
+       void (*get_rate)(void *priv, struct net_device *dev,
+                        struct ieee80211_supported_band *band,
+                        struct sk_buff *skb,
+                        struct rate_selection *sel);
        void (*rate_init)(void *priv, void *priv_sta,
                          struct ieee80211_local *local, struct sta_info *sta);
        void (*clear)(void *priv);
@@ -72,25 +67,21 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
  * first available algorithm. */
 struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local);
+void rate_control_get_rate(struct net_device *dev,
+                          struct ieee80211_supported_band *sband,
+                          struct sk_buff *skb,
+                          struct rate_selection *sel);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
-static inline void rate_control_tx_status(struct ieee80211_local *local,
-                                         struct net_device *dev,
+static inline void rate_control_tx_status(struct net_device *dev,
                                          struct sk_buff *skb,
                                          struct ieee80211_tx_status *status)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct rate_control_ref *ref = local->rate_ctrl;
-       ref->ops->tx_status(ref->priv, dev, skb, status);
-}
-
 
-static inline struct ieee80211_rate *
-rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
-                     struct sk_buff *skb, struct rate_control_extra *extra)
-{
-       struct rate_control_ref *ref = local->rate_ctrl;
-       return ref->ops->get_rate(ref->priv, dev, skb, extra);
+       ref->ops->tx_status(ref->priv, dev, skb, status);
 }
 
 
@@ -139,10 +130,74 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 #endif
 }
 
+static inline int rate_supported(struct sta_info *sta,
+                                enum ieee80211_band band,
+                                int index)
+{
+       return (sta == NULL || sta->supp_rates[band] & BIT(index));
+}
+
+static inline int
+rate_lowest_index(struct ieee80211_local *local,
+                 struct ieee80211_supported_band *sband,
+                 struct sta_info *sta)
+{
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++)
+               if (rate_supported(sta, sband->band, i))
+                       return i;
+
+       /* warn when we cannot find a rate. */
+       WARN_ON(1);
+
+       return 0;
+}
+
+static inline struct ieee80211_rate *
+rate_lowest(struct ieee80211_local *local,
+           struct ieee80211_supported_band *sband,
+           struct sta_info *sta)
+{
+       return &sband->bitrates[rate_lowest_index(local, sband, sta)];
+}
+
 
 /* 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);
 
+
+/* Rate control algorithms */
+#if defined(RC80211_SIMPLE_COMPILE) || \
+       (defined(CONFIG_MAC80211_RC_SIMPLE) && \
+        !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE))
+extern int rc80211_simple_init(void);
+extern void rc80211_simple_exit(void);
+#else
+static inline int rc80211_simple_init(void)
+{
+       return 0;
+}
+static inline void rc80211_simple_exit(void)
+{
+}
+#endif
+
+#if defined(RC80211_PID_COMPILE) || \
+       (defined(CONFIG_MAC80211_RC_PID) && \
+        !defined(CONFIG_MAC80211_RC_PID_MODULE))
+extern int rc80211_pid_init(void);
+extern void rc80211_pid_exit(void);
+#else
+static inline int rc80211_pid_init(void)
+{
+       return 0;
+}
+static inline void rc80211_pid_exit(void)
+{
+}
+#endif
+
 #endif /* IEEE80211_RATE_H */
index 7c93f29c8bd46ba97f1777e1c954574069fd4993..92d7450e2c3be7ed9bb84696989d5301d65e4949 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 /* TODO:
- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
  * order BSS list by RSSI(?) ("quality of AP")
  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
  *    SSID)
 
 #define ERP_INFO_USE_PROTECTION BIT(1)
 
+/* mgmt header + 1 byte action code */
+#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
+
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/* next values represent the buffer size for A-MPDU frame.
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                                     u8 *ssid, size_t ssid_len);
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
+                    u8 *ssid, u8 ssid_len);
 static void ieee80211_rx_bss_put(struct net_device *dev,
                                 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
@@ -90,7 +104,8 @@ struct ieee802_11_elems {
        u8 *ext_supp_rates;
        u8 *wmm_info;
        u8 *wmm_param;
-
+       u8 *ht_cap_elem;
+       u8 *ht_info_elem;
        /* length of them, respectively */
        u8 ssid_len;
        u8 supp_rates_len;
@@ -106,16 +121,15 @@ struct ieee802_11_elems {
        u8 ext_supp_rates_len;
        u8 wmm_info_len;
        u8 wmm_param_len;
+       u8 ht_cap_elem_len;
+       u8 ht_info_elem_len;
 };
 
-enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
-
-static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
-                                           struct ieee802_11_elems *elems)
+static void ieee802_11_parse_elems(u8 *start, size_t len,
+                                  struct ieee802_11_elems *elems)
 {
        size_t left = len;
        u8 *pos = start;
-       int unknown = 0;
 
        memset(elems, 0, sizeof(*elems));
 
@@ -126,15 +140,8 @@ static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
                elen = *pos++;
                left -= 2;
 
-               if (elen > left) {
-#if 0
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "IEEE 802.11 element parse "
-                                      "failed (id=%d elen=%d left=%d)\n",
-                                      id, elen, left);
-#endif
-                       return ParseFailed;
-               }
+               if (elen > left)
+                       return;
 
                switch (id) {
                case WLAN_EID_SSID:
@@ -200,29 +207,24 @@ static enum 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_elem = pos;
+                       elems->ht_cap_elem_len = elen;
+                       break;
+               case WLAN_EID_HT_EXTRA_INFO:
+                       elems->ht_info_elem = pos;
+                       elems->ht_info_elem_len = elen;
+                       break;
                default:
-#if 0
-                       printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
-                                     "unknown element (id=%d elen=%d)\n",
-                                     id, elen);
-#endif
-                       unknown++;
                        break;
                }
 
                left -= elen;
                pos += elen;
        }
-
-       /* Do not trigger error if left == 1 as Apple Airport base stations
-        * send AssocResps that are one spurious byte too long. */
-
-       return unknown ? ParseUnknown : ParseOK;
 }
 
 
-
-
 static int ecw2cw(int ecw)
 {
        int cw = 1;
@@ -311,49 +313,89 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 }
 
 
-static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
+                                  u8 erp_value)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
        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;
+       bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+       bool preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
+       DECLARE_MAC_BUF(mac);
+       u32 changed = 0;
 
-       if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) {
+       if (use_protection != bss_conf->use_cts_prot) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
-                              MAC_FMT ")\n",
-                              dev->name,
+                              "%s)\n",
+                              sdata->dev->name,
                               use_protection ? "enabled" : "disabled",
-                              MAC_ARG(ifsta->bssid));
+                              print_mac(mac, ifsta->bssid));
                }
-               if (use_protection)
-                       sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
-               else
-                       sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
-               changes |= IEEE80211_ERP_CHANGE_PROTECTION;
+               bss_conf->use_cts_prot = use_protection;
+               changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
 
-       if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) {
+       if (preamble_mode != bss_conf->use_short_preamble) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: switched to %s barker preamble"
-                              " (BSSID=" MAC_FMT ")\n",
-                              dev->name,
+                              " (BSSID=%s)\n",
+                              sdata->dev->name,
                               (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?
                                        "short" : "long",
-                              MAC_ARG(ifsta->bssid));
+                              print_mac(mac, ifsta->bssid));
                }
-               if (preamble_mode)
-                       sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
-               else
-                       sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
-               changes |= IEEE80211_ERP_CHANGE_PREAMBLE;
+               bss_conf->use_short_preamble = preamble_mode;
+               changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
 
-       if (changes)
-               ieee80211_erp_info_change_notify(dev, changes);
+       return changed;
+}
+
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+                                  struct ieee80211_ht_info *ht_info)
+{
+
+       if (ht_info == NULL)
+               return -EINVAL;
+
+       memset(ht_info, 0, sizeof(*ht_info));
+
+       if (ht_cap_ie) {
+               u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+
+               ht_info->ht_supported = 1;
+               ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
+               ht_info->ampdu_factor =
+                       ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
+               ht_info->ampdu_density =
+                       (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+               memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
+       } else
+               ht_info->ht_supported = 0;
+
+       return 0;
 }
 
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                       struct ieee80211_ht_addt_info *ht_add_info_ie,
+                       struct ieee80211_ht_bss_info *bss_info)
+{
+       if (bss_info == NULL)
+               return -EINVAL;
+
+       memset(bss_info, 0, sizeof(*bss_info));
+
+       if (ht_add_info_ie) {
+               u16 op_mode;
+               op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
+
+               bss_info->primary_channel = ht_add_info_ie->control_chan;
+               bss_info->bss_cap = ht_add_info_ie->ht_param;
+               bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+       }
+
+       return 0;
+}
 
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
                                         struct ieee80211_if_sta *ifsta)
@@ -410,26 +452,26 @@ static void ieee80211_set_associated(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta,
                                     bool assoc)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        union iwreq_data wrqu;
-
-       if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc)
-               return;
+       u32 changed = BSS_CHANGED_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)
+               if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                        return;
 
-               bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+               bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+                                          local->hw.conf.channel->center_freq,
+                                          ifsta->ssid, ifsta->ssid_len);
                if (bss) {
                        if (bss->has_erp_value)
-                               ieee80211_handle_erp_ie(dev, bss->erp_value);
+                               changed |= ieee80211_handle_erp_ie(
+                                               sdata, bss->erp_value);
                        ieee80211_rx_bss_put(dev, bss);
                }
 
@@ -449,6 +491,9 @@ static void ieee80211_set_associated(struct net_device *dev,
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
        ifsta->last_probe = jiffies;
        ieee80211_led_assoc(local, assoc);
+
+       sdata->bss_conf.assoc = assoc;
+       ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 static void ieee80211_set_disassoc(struct net_device *dev,
@@ -523,18 +568,20 @@ static void ieee80211_send_auth(struct net_device *dev,
 static void ieee80211_authenticate(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta)
 {
+       DECLARE_MAC_BUF(mac);
+
        ifsta->auth_tries++;
        if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT
+               printk(KERN_DEBUG "%s: authentication with AP %s"
                       " timed out\n",
-                      dev->name, MAC_ARG(ifsta->bssid));
+                      dev->name, print_mac(mac, ifsta->bssid));
                ifsta->state = IEEE80211_DISABLED;
                return;
        }
 
        ifsta->state = IEEE80211_AUTHENTICATE;
-       printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n",
-              dev->name, MAC_ARG(ifsta->bssid));
+       printk(KERN_DEBUG "%s: authenticate with AP %s\n",
+              dev->name, print_mac(mac, ifsta->bssid));
 
        ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
 
@@ -546,7 +593,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
                                 struct ieee80211_if_sta *ifsta)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u8 *pos, *ies;
@@ -554,6 +600,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
        u16 capab;
        struct ieee80211_sta_bss *bss;
        int wmm = 0;
+       struct ieee80211_supported_band *sband;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -565,13 +612,20 @@ static void ieee80211_send_assoc(struct net_device *dev,
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       mode = local->oper_hw_mode;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
        capab = ifsta->capab;
-       if (mode->mode == MODE_IEEE80211G) {
-               capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-                       WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
+               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+                       capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+                       capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
        }
-       bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+
+       bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+                                  local->hw.conf.channel->center_freq,
+                                  ifsta->ssid, ifsta->ssid_len);
        if (bss) {
                if (bss->capability & WLAN_CAPABILITY_PRIVACY)
                        capab |= WLAN_CAPABILITY_PRIVACY;
@@ -609,23 +663,23 @@ static void ieee80211_send_assoc(struct net_device *dev,
        *pos++ = ifsta->ssid_len;
        memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-       len = mode->num_rates;
+       len = sband->n_bitrates;
        if (len > 8)
                len = 8;
        pos = skb_put(skb, len + 2);
        *pos++ = WLAN_EID_SUPP_RATES;
        *pos++ = len;
        for (i = 0; i < len; i++) {
-               int rate = mode->rates[i].rate;
+               int rate = sband->bitrates[i].bitrate;
                *pos++ = (u8) (rate / 5);
        }
 
-       if (mode->num_rates > len) {
-               pos = skb_put(skb, mode->num_rates - len + 2);
+       if (sband->n_bitrates > len) {
+               pos = skb_put(skb, sband->n_bitrates - len + 2);
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = mode->num_rates - len;
-               for (i = len; i < mode->num_rates; i++) {
-                       int rate = mode->rates[i].rate;
+               *pos++ = sband->n_bitrates - len;
+               for (i = len; i < sband->n_bitrates; i++) {
+                       int rate = sband->bitrates[i].bitrate;
                        *pos++ = (u8) (rate / 5);
                }
        }
@@ -647,6 +701,20 @@ static void ieee80211_send_assoc(struct net_device *dev,
                *pos++ = 1; /* WME ver */
                *pos++ = 0;
        }
+       /* wmm support is a must to HT */
+       if (wmm && sband->ht_info.ht_supported) {
+               __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+               pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
+               *pos++ = WLAN_EID_HT_CAPABILITY;
+               *pos++ = sizeof(struct ieee80211_ht_cap);
+               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+               memcpy(pos, &tmp, sizeof(u16));
+               pos += sizeof(u16);
+               /* TODO: needs a define here for << 2 */
+               *pos++ = sband->ht_info.ampdu_factor |
+                        (sband->ht_info.ampdu_density << 2);
+               memcpy(pos, sband->ht_info.supp_mcs_set, 16);
+       }
 
        kfree(ifsta->assocreq_ies);
        ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
@@ -719,42 +787,51 @@ static void ieee80211_send_disassoc(struct net_device *dev,
 static int ieee80211_privacy_mismatch(struct net_device *dev,
                                      struct ieee80211_if_sta *ifsta)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
-       int res = 0;
+       int bss_privacy;
+       int wep_privacy;
+       int privacy_invoked;
 
-       if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
-           ifsta->key_management_enabled)
+       if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
                return 0;
 
-       bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+       bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+                                  local->hw.conf.channel->center_freq,
+                                  ifsta->ssid, ifsta->ssid_len);
        if (!bss)
                return 0;
 
-       if (ieee80211_sta_wep_configured(dev) !=
-           !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
-               res = 1;
+       bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
+       wep_privacy = !!ieee80211_sta_wep_configured(dev);
+       privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
        ieee80211_rx_bss_put(dev, bss);
 
-       return res;
+       if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
+               return 0;
+
+       return 1;
 }
 
 
 static void ieee80211_associate(struct net_device *dev,
                                struct ieee80211_if_sta *ifsta)
 {
+       DECLARE_MAC_BUF(mac);
+
        ifsta->assoc_tries++;
        if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: association with AP " MAC_FMT
+               printk(KERN_DEBUG "%s: association with AP %s"
                       " timed out\n",
-                      dev->name, MAC_ARG(ifsta->bssid));
+                      dev->name, print_mac(mac, ifsta->bssid));
                ifsta->state = IEEE80211_DISABLED;
                return;
        }
 
        ifsta->state = IEEE80211_ASSOCIATE;
-       printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n",
-              dev->name, MAC_ARG(ifsta->bssid));
+       printk(KERN_DEBUG "%s: associate with AP %s\n",
+              dev->name, print_mac(mac, ifsta->bssid));
        if (ieee80211_privacy_mismatch(dev, ifsta)) {
                printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
                       "mixed-cell disabled - abort association\n", dev->name);
@@ -774,6 +851,7 @@ static void ieee80211_associated(struct net_device *dev,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
        int disassoc;
+       DECLARE_MAC_BUF(mac);
 
        /* TODO: start monitoring current AP signal quality and number of
         * missed beacons. Scan other channels every now and then and search
@@ -784,8 +862,8 @@ static void ieee80211_associated(struct net_device *dev,
 
        sta = sta_info_get(local, ifsta->bssid);
        if (!sta) {
-               printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n",
-                      dev->name, MAC_ARG(ifsta->bssid));
+               printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
+                      dev->name, print_mac(mac, ifsta->bssid));
                disassoc = 1;
        } else {
                disassoc = 0;
@@ -793,9 +871,9 @@ static void ieee80211_associated(struct net_device *dev,
                               sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
                        if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
                                printk(KERN_DEBUG "%s: No ProbeResp from "
-                                      "current AP " MAC_FMT " - assume out of "
+                                      "current AP %s - assume out of "
                                       "range\n",
-                                      dev->name, MAC_ARG(ifsta->bssid));
+                                      dev->name, print_mac(mac, ifsta->bssid));
                                disassoc = 1;
                                sta_info_free(sta);
                        } else
@@ -816,12 +894,8 @@ static void ieee80211_associated(struct net_device *dev,
                sta_info_put(sta);
        }
        if (disassoc) {
-               union iwreq_data wrqu;
-               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
-               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-               wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-               mod_timer(&ifsta->timer, jiffies +
-                                     IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+               ifsta->state = IEEE80211_DISABLED;
+               ieee80211_set_associated(dev, ifsta, 0);
        } else {
                mod_timer(&ifsta->timer, jiffies +
                                      IEEE80211_MONITORING_INTERVAL);
@@ -833,7 +907,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                                     u8 *ssid, size_t ssid_len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
+       struct ieee80211_supported_band *sband;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u8 *pos, *supp_rates, *esupp_rates = NULL;
@@ -867,11 +941,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
        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;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               struct ieee80211_rate *rate = &sband->bitrates[i];
                if (esupp_rates) {
                        pos = skb_put(skb, 1);
                        esupp_rates[1]++;
@@ -884,7 +957,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                        pos = skb_put(skb, 1);
                        supp_rates[1]++;
                }
-               *pos = rate->rate / 5;
+               *pos = rate->bitrate / 5;
        }
 
        ieee80211_sta_tx(dev, skb, 0);
@@ -920,12 +993,7 @@ static void ieee80211_auth_challenge(struct net_device *dev,
 
        printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
        pos = mgmt->u.auth.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
-           == ParseFailed) {
-               printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
-                      dev->name);
-               return;
-       }
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
        if (!elems.challenge) {
                printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
                       "frame\n", dev->name);
@@ -935,6 +1003,503 @@ static void ieee80211_auth_challenge(struct net_device *dev,
                            elems.challenge_len + 2, 1);
 }
 
+static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
+                                       u8 dialog_token, u16 status, u16 policy,
+                                       u16 buf_size, u16 timeout)
+{
+       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;
+       u16 capab;
+
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+                                       sizeof(mgmt->u.action.u.addba_resp));
+       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, da, ETH_ALEN);
+       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+               memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+       else
+               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 = dialog_token;
+
+       capab = (u16)(policy << 1);     /* bit 1 aggregation policy */
+       capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
+       capab |= (u16)(buf_size << 6);  /* bit 15:6 max size of aggregation */
+
+       mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+       mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+       mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+       ieee80211_sta_tx(dev, skb, 0);
+
+       return;
+}
+
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+                               u16 tid, u8 dialog_token, u16 start_seq_num,
+                               u16 agg_size, u16 timeout)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u16 capab;
+
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+                               sizeof(mgmt->u.action.u.addba_req));
+
+
+       if (!skb) {
+               printk(KERN_ERR "%s: failed to allocate buffer "
+                               "for addba request 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, da, ETH_ALEN);
+       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+               memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+       else
+               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_req));
+
+       mgmt->u.action.category = WLAN_CATEGORY_BACK;
+       mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+       mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+       capab = (u16)(1 << 1);          /* bit 1 aggregation policy */
+       capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
+       capab |= (u16)(agg_size << 6);  /* bit 15:6 max size of aggergation */
+
+       mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+       mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+       mgmt->u.action.u.addba_req.start_seq_num =
+                                       cpu_to_le16(start_seq_num << 4);
+
+       ieee80211_sta_tx(dev, skb, 0);
+}
+
+static void ieee80211_sta_process_addba_request(struct net_device *dev,
+                                               struct ieee80211_mgmt *mgmt,
+                                               size_t len)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hw *hw = &local->hw;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct sta_info *sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
+       u8 dialog_token;
+       int ret = -EOPNOTSUPP;
+       DECLARE_MAC_BUF(mac);
+
+       sta = sta_info_get(local, mgmt->sa);
+       if (!sta)
+               return;
+
+       /* extract session parameters from addba request frame */
+       dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+       timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+       start_seq_num =
+               le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
+
+       capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+       ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+       tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+       buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+       status = WLAN_STATUS_REQUEST_DECLINED;
+
+       /* sanity check for incoming parameters:
+        * check if configuration can support the BA policy
+        * and if buffer size does not exceeds max value */
+       if (((ba_policy != 1)
+               && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
+               || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+               status = WLAN_STATUS_INVALID_QOS_PARAM;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "Block Ack Req with bad params from "
+                               "%s on tid %u. policy %d, buffer size %d\n",
+                               print_mac(mac, mgmt->sa), tid, ba_policy,
+                               buf_size);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               goto end_no_lock;
+       }
+       /* determine default buffer size */
+       if (buf_size == 0) {
+               struct ieee80211_supported_band *sband;
+
+               sband = local->hw.wiphy->bands[conf->channel->band];
+               buf_size = IEEE80211_MIN_AMPDU_BUF;
+               buf_size = buf_size << sband->ht_info.ampdu_factor;
+       }
+
+       tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
+
+       /* examine state machine */
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+       if (tid_agg_rx->state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "unexpected Block Ack Req from "
+                               "%s on tid %u\n",
+                               print_mac(mac, mgmt->sa), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               goto end;
+       }
+
+       /* prepare reordering buffer */
+       tid_agg_rx->reorder_buf =
+               kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
+       if ((!tid_agg_rx->reorder_buf) && net_ratelimit()) {
+               printk(KERN_ERR "can not allocate reordering buffer "
+                                               "to tid %d\n", tid);
+               goto end;
+       }
+       memset(tid_agg_rx->reorder_buf, 0,
+               buf_size * sizeof(struct sk_buf *));
+
+       if (local->ops->ampdu_action)
+               ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
+                                              sta->addr, tid, &start_seq_num);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+       if (ret) {
+               kfree(tid_agg_rx->reorder_buf);
+               goto end;
+       }
+
+       /* change state and send addba resp */
+       tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL;
+       tid_agg_rx->dialog_token = dialog_token;
+       tid_agg_rx->ssn = start_seq_num;
+       tid_agg_rx->head_seq_num = start_seq_num;
+       tid_agg_rx->buf_size = buf_size;
+       tid_agg_rx->timeout = timeout;
+       tid_agg_rx->stored_mpdu_num = 0;
+       status = WLAN_STATUS_SUCCESS;
+end:
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+end_no_lock:
+       ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
+                               status, 1, buf_size, timeout);
+       sta_info_put(sta);
+}
+
+static void ieee80211_sta_process_addba_resp(struct net_device *dev,
+                                            struct ieee80211_mgmt *mgmt,
+                                            size_t len)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hw *hw = &local->hw;
+       struct sta_info *sta;
+       u16 capab;
+       u16 tid;
+       u8 *state;
+
+       sta = sta_info_get(local, mgmt->sa);
+       if (!sta)
+               return;
+
+       capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+       tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+       if (mgmt->u.action.u.addba_resp.dialog_token !=
+               sta->ampdu_mlme.tid_tx[tid].dialog_token) {
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+               sta_info_put(sta);
+               return;
+       }
+
+       del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+       if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+                       == WLAN_STATUS_SUCCESS) {
+               if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+                       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+                       printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
+                               "%d\n", *state);
+                       sta_info_put(sta);
+                       return;
+               }
+
+               if (*state & HT_ADDBA_RECEIVED_MSK)
+                       printk(KERN_DEBUG "double addBA response\n");
+
+               *state |= HT_ADDBA_RECEIVED_MSK;
+               sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+
+               if (*state == HT_AGG_STATE_OPERATIONAL) {
+                       printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+                       ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               }
+
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
+       } else {
+               printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
+
+               sta->ampdu_mlme.tid_tx[tid].addba_req_num++;
+               /* this will allow the state check in stop_BA_session */
+               *state = HT_AGG_STATE_OPERATIONAL;
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
+                                            WLAN_BACK_INITIATOR);
+       }
+       sta_info_put(sta);
+}
+
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+                         u16 initiator, u16 reason_code)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u16 params;
+
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+                                       sizeof(mgmt->u.action.u.delba));
+
+       if (!skb) {
+               printk(KERN_ERR "%s: failed to allocate buffer "
+                                       "for delba 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, da, ETH_ALEN);
+       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+               memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+       else
+               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.delba));
+
+       mgmt->u.action.category = WLAN_CATEGORY_BACK;
+       mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+       params = (u16)(initiator << 11);        /* bit 11 initiator */
+       params |= (u16)(tid << 12);             /* bit 15:12 TID number */
+
+       mgmt->u.action.u.delba.params = cpu_to_le16(params);
+       mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
+
+       ieee80211_sta_tx(dev, skb, 0);
+}
+
+void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
+                                       u16 initiator, u16 reason)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hw *hw = &local->hw;
+       struct sta_info *sta;
+       int ret, i;
+
+       sta = sta_info_get(local, ra);
+       if (!sta)
+               return;
+
+       /* check if TID is in operational state */
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+       if (sta->ampdu_mlme.tid_rx[tid].state
+                               != HT_AGG_STATE_OPERATIONAL) {
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+               sta_info_put(sta);
+               return;
+       }
+       sta->ampdu_mlme.tid_rx[tid].state =
+               HT_AGG_STATE_REQ_STOP_BA_MSK |
+               (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+       /* stop HW Rx aggregation. ampdu_action existence
+        * already verified in session init so we add the BUG_ON */
+       BUG_ON(!local->ops->ampdu_action);
+
+       ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+                                       ra, tid, NULL);
+       if (ret)
+               printk(KERN_DEBUG "HW problem - can not stop rx "
+                               "aggergation for tid %d\n", tid);
+
+       /* shutdown timer has not expired */
+       if (initiator != WLAN_BACK_TIMER)
+               del_timer_sync(&sta->ampdu_mlme.tid_rx[tid].
+                                       session_timer);
+
+       /* check if this is a self generated aggregation halt */
+       if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+               ieee80211_send_delba(dev, ra, tid, 0, reason);
+
+       /* free the reordering buffer */
+       for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) {
+               if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) {
+                       /* release the reordered frames */
+                       dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]);
+                       sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--;
+                       sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL;
+               }
+       }
+       kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
+
+       sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
+       sta_info_put(sta);
+}
+
+
+static void ieee80211_sta_process_delba(struct net_device *dev,
+                       struct ieee80211_mgmt *mgmt, size_t len)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       u16 tid, params;
+       u16 initiator;
+       DECLARE_MAC_BUF(mac);
+
+       sta = sta_info_get(local, mgmt->sa);
+       if (!sta)
+               return;
+
+       params = le16_to_cpu(mgmt->u.action.u.delba.params);
+       tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
+       initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       if (net_ratelimit())
+               printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
+                       print_mac(mac, mgmt->sa),
+                       initiator ? "recipient" : "initiator", tid,
+                       mgmt->u.action.u.delba.reason_code);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+       if (initiator == WLAN_BACK_INITIATOR)
+               ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
+                                                WLAN_BACK_INITIATOR, 0);
+       else { /* WLAN_BACK_RECIPIENT */
+               spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+               sta->ampdu_mlme.tid_tx[tid].state =
+                               HT_AGG_STATE_OPERATIONAL;
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
+                                            WLAN_BACK_RECIPIENT);
+       }
+       sta_info_put(sta);
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+void sta_addba_resp_timer_expired(unsigned long data)
+{
+       /* not an elegant detour, but there is no choice as the timer passes
+        * only one argument, and both sta_info and TID are needed, so init
+        * flow in sta_info_add gives the TID as data, while the timer_to_id
+        * array gives the sta through container_of */
+       u16 tid = *(int *)data;
+       struct sta_info *temp_sta = container_of((void *)data,
+               struct sta_info, timer_to_tid[tid]);
+
+       struct ieee80211_local *local = temp_sta->local;
+       struct ieee80211_hw *hw = &local->hw;
+       struct sta_info *sta;
+       u8 *state;
+
+       sta = sta_info_get(local, temp_sta->addr);
+       if (!sta)
+               return;
+
+       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       /* check if the TID waits for addBA response */
+       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               *state = HT_AGG_STATE_IDLE;
+               printk(KERN_DEBUG "timer expired on tid %d but we are not "
+                               "expecting addBA response there", tid);
+               goto timer_expired_exit;
+       }
+
+       printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+
+       /* go through the state check in stop_BA_session */
+       *state = HT_AGG_STATE_OPERATIONAL;
+       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
+                                    WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+       sta_info_put(sta);
+}
+
+/*
+ * After receiving Block Ack Request (BAR) we activated a
+ * timer after each frame arrives from the originator.
+ * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
+ */
+void sta_rx_agg_session_timer_expired(unsigned long data)
+{
+       /* not an elegant detour, but there is no choice as the timer passes
+        * only one argument, and verious sta_info are needed here, so init
+        * flow in sta_info_add gives the TID as data, while the timer_to_id
+        * array gives the sta through container_of */
+       u8 *ptid = (u8 *)data;
+       u8 *timer_to_id = ptid - *ptid;
+       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+                                        timer_to_tid[0]);
+
+       printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+       ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid,
+                                        WLAN_BACK_TIMER,
+                                        WLAN_REASON_QSTA_TIMEOUT);
+}
+
 
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
@@ -943,37 +1508,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        u16 auth_alg, auth_transaction, status_code;
+       DECLARE_MAC_BUF(mac);
 
        if (ifsta->state != IEEE80211_AUTHENTICATE &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS) {
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
                printk(KERN_DEBUG "%s: authentication frame received from "
-                      MAC_FMT ", but not in authenticate state - ignored\n",
-                      dev->name, MAC_ARG(mgmt->sa));
+                      "%s, but not in authenticate state - ignored\n",
+                      dev->name, print_mac(mac, mgmt->sa));
                return;
        }
 
        if (len < 24 + 6) {
                printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
-                      "received from " MAC_FMT " - ignored\n",
-                      dev->name, len, MAC_ARG(mgmt->sa));
+                      "received from %s - ignored\n",
+                      dev->name, len, print_mac(mac, mgmt->sa));
                return;
        }
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+       if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
            memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
                printk(KERN_DEBUG "%s: authentication frame received from "
-                      "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-                      "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-                      MAC_ARG(mgmt->bssid));
+                      "unknown AP (SA=%s BSSID=%s) - "
+                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+                      print_mac(mac, mgmt->bssid));
                return;
        }
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+       if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
            memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
                printk(KERN_DEBUG "%s: authentication frame received from "
-                      "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-                      "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-                      MAC_ARG(mgmt->bssid));
+                      "unknown BSSID (SA=%s BSSID=%s) - "
+                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+                      print_mac(mac, mgmt->bssid));
                return;
        }
 
@@ -981,12 +1547,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-       printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d "
+       printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d "
               "transaction=%d status=%d)\n",
-              dev->name, MAC_ARG(mgmt->sa), auth_alg,
+              dev->name, print_mac(mac, mgmt->sa), auth_alg,
               auth_transaction, status_code);
 
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                /* IEEE 802.11 standard does not require authentication in IBSS
                 * networks and most implementations do not seem to use it.
                 * However, try to reply to authentication attempts if someone
@@ -1070,27 +1636,28 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
                                     size_t len)
 {
        u16 reason_code;
+       DECLARE_MAC_BUF(mac);
 
        if (len < 24 + 2) {
                printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
-                      "received from " MAC_FMT " - ignored\n",
-                      dev->name, len, MAC_ARG(mgmt->sa));
+                      "received from %s - ignored\n",
+                      dev->name, len, print_mac(mac, mgmt->sa));
                return;
        }
 
        if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
                printk(KERN_DEBUG "%s: deauthentication frame received from "
-                      "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-                      "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-                      MAC_ARG(mgmt->bssid));
+                      "unknown AP (SA=%s BSSID=%s) - "
+                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+                      print_mac(mac, mgmt->bssid));
                return;
        }
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT
+       printk(KERN_DEBUG "%s: RX deauthentication from %s"
               " (reason=%d)\n",
-              dev->name, MAC_ARG(mgmt->sa), reason_code);
+              dev->name, print_mac(mac, mgmt->sa), reason_code);
 
        if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
                printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
@@ -1115,27 +1682,28 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
                                       size_t len)
 {
        u16 reason_code;
+       DECLARE_MAC_BUF(mac);
 
        if (len < 24 + 2) {
                printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
-                      "received from " MAC_FMT " - ignored\n",
-                      dev->name, len, MAC_ARG(mgmt->sa));
+                      "received from %s - ignored\n",
+                      dev->name, len, print_mac(mac, mgmt->sa));
                return;
        }
 
        if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
                printk(KERN_DEBUG "%s: disassociation frame received from "
-                      "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-                      "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-                      MAC_ARG(mgmt->bssid));
+                      "unknown AP (SA=%s BSSID=%s) - "
+                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+                      print_mac(mac, mgmt->bssid));
                return;
        }
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT
+       printk(KERN_DEBUG "%s: RX disassociation from %s"
               " (reason=%d)\n",
-              dev->name, MAC_ARG(mgmt->sa), reason_code);
+              dev->name, print_mac(mac, mgmt->sa), reason_code);
 
        if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
                printk(KERN_DEBUG "%s: disassociated\n", dev->name);
@@ -1150,58 +1718,58 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
 }
 
 
-static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
+static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                                         struct ieee80211_if_sta *ifsta,
                                         struct ieee80211_mgmt *mgmt,
                                         size_t len,
                                         int reassoc)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
+       struct ieee80211_local *local = sdata->local;
+       struct net_device *dev = sdata->dev;
+       struct ieee80211_supported_band *sband;
        struct sta_info *sta;
-       u32 rates;
+       u64 rates, basic_rates;
        u16 capab_info, status_code, aid;
        struct ieee802_11_elems elems;
+       struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
        u8 *pos;
        int i, j;
+       DECLARE_MAC_BUF(mac);
+       bool have_higher_than_11mbit = false;
 
        /* AssocResp and ReassocResp have identical structure, so process both
         * of them in this function. */
 
        if (ifsta->state != IEEE80211_ASSOCIATE) {
                printk(KERN_DEBUG "%s: association frame received from "
-                      MAC_FMT ", but not in associate state - ignored\n",
-                      dev->name, MAC_ARG(mgmt->sa));
+                      "%s, but not in associate state - ignored\n",
+                      dev->name, print_mac(mac, mgmt->sa));
                return;
        }
 
        if (len < 24 + 6) {
                printk(KERN_DEBUG "%s: too short (%zd) association frame "
-                      "received from " MAC_FMT " - ignored\n",
-                      dev->name, len, MAC_ARG(mgmt->sa));
+                      "received from %s - ignored\n",
+                      dev->name, len, print_mac(mac, mgmt->sa));
                return;
        }
 
        if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
                printk(KERN_DEBUG "%s: association frame received from "
-                      "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-                      "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-                      MAC_ARG(mgmt->bssid));
+                      "unknown AP (SA=%s BSSID=%s) - "
+                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+                      print_mac(mac, mgmt->bssid));
                return;
        }
 
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
        aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
-       if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-               printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-                      "set\n", dev->name, aid);
-       aid &= ~(BIT(15) | BIT(14));
 
-       printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x "
+       printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x "
               "status=%d aid=%d)\n",
-              dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa),
-              capab_info, status_code, aid);
+              dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
+              capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
@@ -1213,13 +1781,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
                return;
        }
 
+       if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+               printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
+                      "set\n", dev->name, aid);
+       aid &= ~(BIT(15) | BIT(14));
+
        pos = mgmt->u.assoc_resp.variable;
-       if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
-           == ParseFailed) {
-               printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
-                      dev->name);
-               return;
-       }
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
        if (!elems.supp_rates) {
                printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
@@ -1227,18 +1795,6 @@ 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;
@@ -1249,8 +1805,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        if (ifsta->assocresp_ies)
                memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
 
-       ieee80211_set_associated(dev, ifsta, 1);
-
        /* Add STA entry for the AP */
        sta = sta_info_get(local, ifsta->bssid);
        if (!sta) {
@@ -1261,7 +1815,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
                               " AP\n", dev->name);
                        return;
                }
-               bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+               bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+                                          local->hw.conf.channel->center_freq,
+                                          ifsta->ssid, ifsta->ssid_len);
                if (bss) {
                        sta->last_rssi = bss->rssi;
                        sta->last_signal = bss->signal;
@@ -1271,23 +1827,63 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        }
 
        sta->dev = dev;
-       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP;
+       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+                     WLAN_STA_AUTHORIZED;
 
        rates = 0;
-       mode = local->oper_hw_mode;
+       basic_rates = 0;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
        for (i = 0; i < elems.supp_rates_len; i++) {
                int rate = (elems.supp_rates[i] & 0x7f) * 5;
-               for (j = 0; j < mode->num_rates; j++)
-                       if (mode->rates[j].rate == rate)
+
+               if (rate > 110)
+                       have_higher_than_11mbit = true;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       if (sband->bitrates[j].bitrate == rate)
                                rates |= BIT(j);
+                       if (elems.supp_rates[i] & 0x80)
+                               basic_rates |= BIT(j);
+               }
        }
+
        for (i = 0; i < elems.ext_supp_rates_len; i++) {
                int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-               for (j = 0; j < mode->num_rates; j++)
-                       if (mode->rates[j].rate == rate)
+
+               if (rate > 110)
+                       have_higher_than_11mbit = true;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       if (sband->bitrates[j].bitrate == rate)
                                rates |= BIT(j);
+                       if (elems.ext_supp_rates[i] & 0x80)
+                               basic_rates |= BIT(j);
+               }
+       }
+
+       sta->supp_rates[local->hw.conf.channel->band] = rates;
+       sdata->basic_rates = basic_rates;
+
+       /* cf. IEEE 802.11 9.2.12 */
+       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+           have_higher_than_11mbit)
+               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+       else
+               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+           local->ops->conf_ht) {
+               struct ieee80211_ht_bss_info bss_info;
+
+               ieee80211_ht_cap_ie_to_ht_info(
+                               (struct ieee80211_ht_cap *)
+                               elems.ht_cap_elem, &sta->ht_info);
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                               (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info);
        }
-       sta->supp_rates = rates;
 
        rate_control_rate_init(sta, local);
 
@@ -1297,6 +1893,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
                                         elems.wmm_param_len);
        }
 
+       /* set AID, ieee80211_set_associated() will tell the driver */
+       bss_conf->aid = aid;
+       ieee80211_set_associated(dev, ifsta, 1);
 
        sta_info_put(sta);
 
@@ -1337,7 +1936,8 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
 
 
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq,
+                    u8 *ssid, u8 ssid_len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
@@ -1348,6 +1948,11 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
        atomic_inc(&bss->users);
        atomic_inc(&bss->users);
        memcpy(bss->bssid, bssid, ETH_ALEN);
+       bss->freq = freq;
+       if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
+               memcpy(bss->ssid, ssid, ssid_len);
+               bss->ssid_len = ssid_len;
+       }
 
        spin_lock_bh(&local->sta_bss_lock);
        /* TODO: order by RSSI? */
@@ -1359,7 +1964,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
 
 
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
+                    u8 *ssid, u8 ssid_len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
@@ -1367,7 +1973,10 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
        spin_lock_bh(&local->sta_bss_lock);
        bss = local->sta_bss_hash[STA_HASH(bssid)];
        while (bss) {
-               if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+               if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
+                   bss->freq == freq &&
+                   bss->ssid_len == ssid_len &&
+                   (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
                        atomic_inc(&bss->users);
                        break;
                }
@@ -1383,6 +1992,7 @@ 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);
 }
 
@@ -1429,19 +2039,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee802_11_elems elems;
        size_t baselen;
-       int channel, invalid = 0, clen;
+       int freq, clen;
        struct ieee80211_sta_bss *bss;
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        u64 timestamp;
+       DECLARE_MAC_BUF(mac);
+       DECLARE_MAC_BUF(mac2);
 
        if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
 #if 0
-       printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n",
+       printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
               dev->name, beacon ? "Beacon" : "Probe Response",
-              MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da));
+              print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
 #endif
 
        baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1450,7 +2062,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
        timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
 
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
            memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                static unsigned long last_tsf_debug = 0;
@@ -1460,10 +2072,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                else
                        tsf = -1LLU;
                if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-                       printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID="
-                              MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld "
+                       printk(KERN_DEBUG "RX beacon SA=%s BSSID="
+                              "%s TSF=0x%llx BCN=0x%llx diff=%lld "
                               "@%lu\n",
-                              MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid),
+                              print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid),
                               (unsigned long long)tsf,
                               (unsigned long long)timestamp,
                               (unsigned long long)(tsf - timestamp),
@@ -1473,23 +2085,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        }
 
-       if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-                                  &elems) == ParseFailed)
-               invalid = 1;
+       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
            memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
            (sta = sta_info_get(local, mgmt->sa))) {
-               struct ieee80211_hw_mode *mode;
-               struct ieee80211_rate *rates;
+               struct ieee80211_supported_band *sband;
+               struct ieee80211_rate *bitrates;
                size_t num_rates;
-               u32 supp_rates, prev_rates;
+               u64 supp_rates, prev_rates;
                int i, j;
 
-               mode = local->sta_scanning ?
-                      local->scan_hw_mode : local->oper_hw_mode;
-               rates = mode->rates;
-               num_rates = mode->num_rates;
+               sband = local->hw.wiphy->bands[rx_status->band];
+
+               if (!sband) {
+                       WARN_ON(1);
+                       sband = local->hw.wiphy->bands[
+                                       local->hw.conf.channel->band];
+               }
+
+               bitrates = sband->bitrates;
+               num_rates = sband->n_bitrates;
 
                supp_rates = 0;
                for (i = 0; i < elems.supp_rates_len +
@@ -1503,24 +2119,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                                        [i - elems.supp_rates_len];
                        own_rate = 5 * (rate & 0x7f);
                        for (j = 0; j < num_rates; j++)
-                               if (rates[j].rate == own_rate)
+                               if (bitrates[j].bitrate == own_rate)
                                        supp_rates |= BIT(j);
                }
 
-               prev_rates = sta->supp_rates;
-               sta->supp_rates &= supp_rates;
-               if (sta->supp_rates == 0) {
+               prev_rates = sta->supp_rates[rx_status->band];
+               sta->supp_rates[rx_status->band] &= supp_rates;
+               if (sta->supp_rates[rx_status->band] == 0) {
                        /* No matching rates - this should not really happen.
                         * Make sure that at least one rate is marked
                         * supported to avoid issues with TX rate ctrl. */
-                       sta->supp_rates = sdata->u.sta.supp_rates_bits;
+                       sta->supp_rates[rx_status->band] =
+                               sdata->u.sta.supp_rates_bits[rx_status->band];
                }
-               if (sta->supp_rates != prev_rates) {
+               if (sta->supp_rates[rx_status->band] != prev_rates) {
                        printk(KERN_DEBUG "%s: updated supp_rates set for "
-                              MAC_FMT " based on beacon info (0x%x & 0x%x -> "
-                              "0x%x)\n",
-                              dev->name, MAC_ARG(sta->addr), prev_rates,
-                              supp_rates, sta->supp_rates);
+                              "%s based on beacon info (0x%llx & 0x%llx -> "
+                              "0x%llx)\n",
+                              dev->name, print_mac(mac, sta->addr),
+                              (unsigned long long) prev_rates,
+                              (unsigned long long) supp_rates,
+                              (unsigned long long) sta->supp_rates[rx_status->band]);
                }
                sta_info_put(sta);
        }
@@ -1529,13 +2148,15 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                return;
 
        if (elems.ds_params && elems.ds_params_len == 1)
-               channel = elems.ds_params[0];
+               freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
        else
-               channel = rx_status->channel;
+               freq = rx_status->freq;
 
-       bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
+       bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
+                                  elems.ssid, elems.ssid_len);
        if (!bss) {
-               bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
+               bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+                                          elems.ssid, elems.ssid_len);
                if (!bss)
                        return;
        } else {
@@ -1547,6 +2168,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif
        }
 
+       bss->band = rx_status->band;
+
        if (bss->probe_resp && beacon) {
                /* Do not allow beacon to override data from Probe Response. */
                ieee80211_rx_bss_put(dev, bss);
@@ -1561,10 +2184,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
        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) {
-               memcpy(bss->ssid, elems.ssid, elems.ssid_len);
-               bss->ssid_len = elems.ssid_len;
-       }
 
        bss->supp_rates_len = 0;
        if (elems.supp_rates) {
@@ -1632,23 +2251,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                bss->wmm_ie = NULL;
                bss->wmm_ie_len = 0;
        }
-
-
-       bss->hw_mode = rx_status->phymode;
-       bss->channel = channel;
-       bss->freq = rx_status->freq;
-       if (channel != rx_status->channel &&
-           (bss->hw_mode == MODE_IEEE80211G ||
-            bss->hw_mode == MODE_IEEE80211B) &&
-           channel >= 1 && channel <= 14) {
-               static const int freq_list[] = {
-                       2412, 2417, 2422, 2427, 2432, 2437, 2442,
-                       2447, 2452, 2457, 2462, 2467, 2472, 2484
-               };
-               /* IEEE 802.11g/b mode can receive packets from neighboring
-                * channels, so map the channel into frequency. */
-               bss->freq = freq_list[channel - 1];
+       if (elems.ht_cap_elem &&
+           (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
+            memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
+               kfree(bss->ht_ie);
+               bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
+               if (bss->ht_ie) {
+                       memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
+                              elems.ht_cap_elem_len + 2);
+                       bss->ht_ie_len = elems.ht_cap_elem_len + 2;
+               } else
+                       bss->ht_ie_len = 0;
+       } else if (!elems.ht_cap_elem && bss->ht_ie) {
+               kfree(bss->ht_ie);
+               bss->ht_ie = NULL;
+               bss->ht_ie_len = 0;
        }
+
        bss->timestamp = timestamp;
        bss->last_update = jiffies;
        bss->rssi = rx_status->ssi;
@@ -1678,11 +2297,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        struct ieee80211_if_sta *ifsta;
        size_t baselen;
        struct ieee802_11_elems elems;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_conf *conf = &local->hw.conf;
+       u32 changed = 0;
 
        ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return;
        ifsta = &sdata->u.sta;
 
@@ -1695,17 +2317,34 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        if (baselen > len)
                return;
 
-       if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-                                  &elems) == ParseFailed)
-               return;
+       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
        if (elems.erp_info && elems.erp_info_len >= 1)
-               ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
+               changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
+
+       if (elems.ht_cap_elem && elems.ht_info_elem &&
+           elems.wmm_param && local->ops->conf_ht &&
+           conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+               struct ieee80211_ht_bss_info bss_info;
+
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                               (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               /* check if AP changed bss inforamation */
+               if ((conf->ht_bss_conf.primary_channel !=
+                    bss_info.primary_channel) ||
+                   (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) ||
+                   (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode))
+                       ieee80211_hw_config_ht(local, 1, &conf->ht_conf,
+                                               &bss_info);
+       }
 
        if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
        }
+
+       ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 
@@ -1721,8 +2360,13 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        struct sk_buff *skb;
        struct ieee80211_mgmt *resp;
        u8 *pos, *end;
+       DECLARE_MAC_BUF(mac);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       DECLARE_MAC_BUF(mac2);
+       DECLARE_MAC_BUF(mac3);
+#endif
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
+       if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS ||
            ifsta->state != IEEE80211_IBSS_JOINED ||
            len < 24 + 2 || !ifsta->probe_resp)
                return;
@@ -1733,10 +2377,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
                tx_last_beacon = 1;
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID="
-              MAC_FMT " (tx_last_beacon=%d)\n",
-              dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da),
-              MAC_ARG(mgmt->bssid), tx_last_beacon);
+       printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID="
+              "%s (tx_last_beacon=%d)\n",
+              dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da),
+              print_mac(mac3, mgmt->bssid), tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
        if (!tx_last_beacon)
@@ -1752,8 +2396,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
            pos + 2 + pos[1] > end) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-                              "from " MAC_FMT "\n",
-                              dev->name, MAC_ARG(mgmt->sa));
+                              "from %s\n",
+                              dev->name, print_mac(mac, mgmt->sa));
                }
                return;
        }
@@ -1772,12 +2416,52 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        resp = (struct ieee80211_mgmt *) skb->data;
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n",
-              dev->name, MAC_ARG(resp->da));
+       printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n",
+              dev->name, print_mac(mac, resp->da));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        ieee80211_sta_tx(dev, skb, 0);
 }
 
+static void ieee80211_rx_mgmt_action(struct net_device *dev,
+                                    struct ieee80211_if_sta *ifsta,
+                                    struct ieee80211_mgmt *mgmt,
+                                    size_t len)
+{
+       if (len < IEEE80211_MIN_ACTION_SIZE)
+               return;
+
+       switch (mgmt->u.action.category) {
+       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;
+                       ieee80211_sta_process_addba_request(dev, mgmt, len);
+                       break;
+               case WLAN_ACTION_ADDBA_RESP:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.addba_resp)))
+                               break;
+                       ieee80211_sta_process_addba_resp(dev, mgmt, len);
+                       break;
+               case WLAN_ACTION_DELBA:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.delba)))
+                               break;
+                       ieee80211_sta_process_delba(dev, mgmt, len);
+                       break;
+               default:
+                       if (net_ratelimit())
+                          printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
+                                       dev->name);
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
 
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
                           struct ieee80211_rx_status *rx_status)
@@ -1807,6 +2491,7 @@ 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;
@@ -1853,10 +2538,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
                ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
                break;
        case IEEE80211_STYPE_ASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0);
+               ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
                break;
        case IEEE80211_STYPE_REASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1);
+               ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
                break;
        case IEEE80211_STYPE_DEAUTH:
                ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
@@ -1864,37 +2549,48 @@ 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);
 }
 
 
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status)
+ieee80211_rx_result
+ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
-       if (skb->len < 24) {
-               dev_kfree_skb(skb);
-               return;
-       }
+       if (skb->len < 2)
+               return RX_DROP_UNUSABLE;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
+       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+               return RX_CONTINUE;
+
+       if (skb->len < 24)
+               return RX_DROP_MONITOR;
+
        if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
                if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
                        ieee80211_rx_mgmt_probe_resp(dev, mgmt,
                                                     skb->len, rx_status);
+                       dev_kfree_skb(skb);
+                       return RX_QUEUED;
                } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
                        ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
                                                 rx_status);
+                       dev_kfree_skb(skb);
+                       return RX_QUEUED;
                }
        }
-
-       dev_kfree_skb(skb);
+       return RX_CONTINUE;
 }
 
 
@@ -1924,13 +2620,14 @@ 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);
+       DECLARE_MAC_BUF(mac);
 
        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));
+                       printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
+                              dev->name, print_mac(mac, sta->addr));
                        __sta_info_get(sta);
                        sta_info_remove(sta);
                        list_add(&sta->list, &tmp_list);
@@ -1983,13 +2680,13 @@ void ieee80211_sta_work(struct work_struct *work)
        if (!netif_running(dev))
                return;
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
                printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
-                      "(type=%d)\n", dev->name, sdata->type);
+                      "(type=%d)\n", dev->name, sdata->vif.type);
                return;
        }
        ifsta = &sdata->u.sta;
@@ -2000,7 +2697,10 @@ void ieee80211_sta_work(struct work_struct *work)
        if (ifsta->state != IEEE80211_AUTHENTICATE &&
            ifsta->state != IEEE80211_ASSOCIATE &&
            test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
-               ieee80211_sta_start_scan(dev, NULL, 0);
+               if (ifsta->scan_ssid_len)
+                       ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len);
+               else
+                       ieee80211_sta_start_scan(dev, NULL, 0);
                return;
        }
 
@@ -2081,7 +2781,7 @@ void ieee80211_sta_req_auth(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);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return;
 
        if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
@@ -2098,7 +2798,8 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
 {
        int tmp, hidden_ssid;
 
-       if (!memcmp(ifsta->ssid, ssid, ssid_len))
+       if (ssid_len == ifsta->ssid_len &&
+           !memcmp(ifsta->ssid, ssid, ssid_len))
                return 1;
 
        if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
@@ -2138,7 +2839,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        }
 
        spin_lock_bh(&local->sta_bss_lock);
-       freq = local->oper_channel->freq;
+       freq = local->oper_channel->center_freq;
        list_for_each_entry(bss, &local->sta_bss_list, list) {
                if (!(bss->capability & WLAN_CAPABILITY_ESS))
                        continue;
@@ -2169,7 +2870,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
        if (selected) {
-               ieee80211_set_channel(local, -1, selected->freq);
+               ieee80211_set_freq(local, selected->freq);
                if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
                        ieee80211_sta_set_ssid(dev, selected->ssid,
                                               selected->ssid_len);
@@ -2202,11 +2903,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_tx_control control;
-       struct ieee80211_rate *rate;
-       struct ieee80211_hw_mode *mode;
-       struct rate_control_extra extra;
+       struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        /* Remove possible STA entries from other IBSS networks. */
        sta_info_flush(local, NULL);
@@ -2226,12 +2928,11 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        sdata->drop_unencrypted = bss->capability &
                WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-       res = ieee80211_set_channel(local, -1, bss->freq);
+       res = ieee80211_set_freq(local, bss->freq);
 
-       if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
-               printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
-                      "(%d MHz)\n", dev->name, local->hw.conf.channel,
-                      local->hw.conf.freq);
+       if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
+               printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+                      "%d MHz\n", dev->name, local->oper_channel->center_freq);
                return -1;
        }
 
@@ -2268,10 +2969,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                *pos++ = rates;
                memcpy(pos, bss->supp_rates, rates);
 
-               pos = skb_put(skb, 2 + 1);
-               *pos++ = WLAN_EID_DS_PARAMS;
-               *pos++ = 1;
-               *pos++ = bss->channel;
+               if (bss->band == IEEE80211_BAND_2GHZ) {
+                       pos = skb_put(skb, 2 + 1);
+                       *pos++ = WLAN_EID_DS_PARAMS;
+                       *pos++ = 1;
+                       *pos++ = ieee80211_frequency_to_channel(bss->freq);
+               }
 
                pos = skb_put(skb, 2 + 2);
                *pos++ = WLAN_EID_IBSS_PARAMS;
@@ -2289,20 +2992,18 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                }
 
                memset(&control, 0, sizeof(control));
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = local->oper_hw_mode;
-               rate = rate_control_get_rate(local, dev, skb, &extra);
-               if (!rate) {
+               rate_control_get_rate(dev, sband, skb, &ratesel);
+               if (!ratesel.rate) {
                        printk(KERN_DEBUG "%s: Failed to determine TX rate "
                               "for IBSS beacon\n", dev->name);
                        break;
                }
-               control.tx_rate =
-                       ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
+               control.vif = &sdata->vif;
+               control.tx_rate = ratesel.rate;
+               if (sdata->bss_conf.use_short_preamble &&
+                   ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+                       control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
                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;
 
@@ -2327,14 +3028,14 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                }
 
                rates = 0;
-               mode = local->oper_hw_mode;
+               sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
                for (i = 0; i < bss->supp_rates_len; i++) {
                        int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-                       for (j = 0; j < mode->num_rates; j++)
-                               if (mode->rates[j].rate == bitrate)
+                       for (j = 0; j < sband->n_bitrates; j++)
+                               if (sband->bitrates[j].bitrate == bitrate)
                                        rates |= BIT(j);
                }
-               ifsta->supp_rates_bits = rates;
+               ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
        } while (0);
 
        if (skb) {
@@ -2357,10 +3058,11 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_hw_mode *mode;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_supported_band *sband;
        u8 bssid[ETH_ALEN], *pos;
        int i;
+       DECLARE_MAC_BUF(mac);
 
 #if 0
        /* Easier testing, use fixed BSSID. */
@@ -2376,32 +3078,31 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        bssid[0] |= 0x02;
 #endif
 
-       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
-              dev->name, MAC_ARG(bssid));
+       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
+              dev->name, print_mac(mac, bssid));
 
-       bss = ieee80211_rx_bss_add(dev, bssid);
+       bss = ieee80211_rx_bss_add(dev, bssid,
+                                  local->hw.conf.channel->center_freq,
+                                  sdata->u.sta.ssid, sdata->u.sta.ssid_len);
        if (!bss)
                return -ENOMEM;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       mode = local->oper_hw_mode;
+       bss->band = local->hw.conf.channel->band;
+       sband = local->hw.wiphy->bands[bss->band];
 
        if (local->hw.conf.beacon_int == 0)
                local->hw.conf.beacon_int = 100;
        bss->beacon_int = local->hw.conf.beacon_int;
-       bss->hw_mode = local->hw.conf.phymode;
-       bss->channel = local->hw.conf.channel;
-       bss->freq = local->hw.conf.freq;
        bss->last_update = jiffies;
        bss->capability = WLAN_CAPABILITY_IBSS;
        if (sdata->default_key) {
                bss->capability |= WLAN_CAPABILITY_PRIVACY;
        } else
                sdata->drop_unencrypted = 0;
-       bss->supp_rates_len = mode->num_rates;
+       bss->supp_rates_len = sband->n_bitrates;
        pos = bss->supp_rates;
-       for (i = 0; i < mode->num_rates; i++) {
-               int rate = mode->rates[i].rate;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               int rate = sband->bitrates[i].bitrate;
                *pos++ = (u8) (rate / 5);
        }
 
@@ -2417,6 +3118,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
        int found = 0;
        u8 bssid[ETH_ALEN];
        int active_ibss;
+       DECLARE_MAC_BUF(mac);
+       DECLARE_MAC_BUF(mac2);
 
        if (ifsta->ssid_len == 0)
                return -EINVAL;
@@ -2433,8 +3136,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
                    || !(bss->capability & WLAN_CAPABILITY_IBSS))
                        continue;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "   bssid=" MAC_FMT " found\n",
-                      MAC_ARG(bss->bssid));
+               printk(KERN_DEBUG "   bssid=%s found\n",
+                      print_mac(mac, bss->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
                memcpy(bssid, bss->bssid, ETH_ALEN);
                found = 1;
@@ -2444,14 +3147,16 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   sta_find_ibss: selected " MAC_FMT " current "
-              MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
+       printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+              "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
-           (bss = ieee80211_rx_bss_get(dev, bssid))) {
-               printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
+           (bss = ieee80211_rx_bss_get(dev, bssid,
+                                       local->hw.conf.channel->center_freq,
+                                       ifsta->ssid, ifsta->ssid_len))) {
+               printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
                       " based on configured SSID\n",
-                      dev->name, MAC_ARG(bssid));
+                      dev->name, print_mac(mac, bssid));
                return ieee80211_sta_join_ibss(dev, ifsta, bss);
        }
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -2475,13 +3180,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
                if (time_after(jiffies, ifsta->ibss_join_req +
                               IEEE80211_IBSS_JOIN_TIMEOUT)) {
                        if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
-                           local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+                           (!(local->oper_channel->flags &
+                                       IEEE80211_CHAN_NO_IBSS)))
                                return ieee80211_sta_create_ibss(dev, ifsta);
                        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,
-                                      local->hw.conf.freq);
+                               printk(KERN_DEBUG "%s: IBSS not allowed on"
+                                      " %d MHz\n", dev->name,
+                                      local->hw.conf.channel->center_freq);
                        }
 
                        /* No IBSS found - decrease scan interval and continue
@@ -2500,7 +3205,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
@@ -2514,18 +3219,23 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
                int i;
 
                memset(&qparam, 0, sizeof(qparam));
-               /* TODO: are these ok defaults for all hw_modes? */
+
                qparam.aifs = 2;
-               qparam.cw_min =
-                       local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
+
+               if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+                   !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+                       qparam.cw_min = 31;
+               else
+                       qparam.cw_min = 15;
+
                qparam.cw_max = 1023;
                qparam.burst_time = 0;
+
                for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-               {
                        local->ops->conf_tx(local_to_hw(local),
                                           i + IEEE80211_TX_QUEUE_DATA0,
                                           &qparam);
-               }
+
                /* IBSS uses different parameters for Beacon sending */
                qparam.cw_min++;
                qparam.cw_min *= 2;
@@ -2534,7 +3244,6 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
                                   IEEE80211_TX_QUEUE_BEACON, &qparam);
        }
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        ifsta = &sdata->u.sta;
 
        if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
@@ -2547,7 +3256,7 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
                ifsta->flags |= IEEE80211_STA_SSID_SET;
        else
                ifsta->flags &= ~IEEE80211_STA_SSID_SET;
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
            !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
                ifsta->ibss_join_req = jiffies;
                ifsta->state = IEEE80211_IBSS_SEARCH;
@@ -2634,11 +3343,17 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        union iwreq_data wrqu;
 
        local->last_scan_completed = jiffies;
-       wmb();
-       local->sta_scanning = 0;
+       memset(&wrqu, 0, sizeof(wrqu));
+       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 
+       if (local->sta_hw_scanning) {
+               local->sta_hw_scanning = 0;
+               goto done;
+       }
+
+       local->sta_sw_scanning = 0;
        if (ieee80211_hw_config(local))
-               printk(KERN_DEBUG "%s: failed to restore operational"
+               printk(KERN_DEBUG "%s: failed to restore operational "
                       "channel after scan\n", dev->name);
 
 
@@ -2652,9 +3367,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
        netif_tx_unlock_bh(local->mdev);
 
-       memset(&wrqu, 0, sizeof(wrqu));
-       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
@@ -2662,7 +3374,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
                if (sdata->dev == local->mdev)
                        continue;
 
-               if (sdata->type == IEEE80211_IF_TYPE_STA) {
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
                        if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
                                ieee80211_send_nullfunc(local, sdata, 0);
                        ieee80211_sta_timer((unsigned long)sdata);
@@ -2672,8 +3384,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        }
        rcu_read_unlock();
 
+done:
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
                if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
                    (!ifsta->state == IEEE80211_IBSS_JOINED &&
@@ -2689,54 +3402,69 @@ void ieee80211_sta_scan_work(struct work_struct *work)
                container_of(work, struct ieee80211_local, scan_work.work);
        struct net_device *dev = local->scan_dev;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_hw_mode *mode;
+       struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
        int skip;
        unsigned long next_delay = 0;
 
-       if (!local->sta_scanning)
+       if (!local->sta_sw_scanning)
                return;
 
        switch (local->scan_state) {
        case SCAN_SET_CHANNEL:
-               mode = local->scan_hw_mode;
-               if (local->scan_hw_mode->list.next == &local->modes_list &&
-                   local->scan_channel_idx >= mode->num_channels) {
+               /*
+                * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
+                * after we successfully scanned the last channel of the last
+                * band (and the last band is supported by the hw)
+                */
+               if (local->scan_band < IEEE80211_NUM_BANDS)
+                       sband = local->hw.wiphy->bands[local->scan_band];
+               else
+                       sband = NULL;
+
+               /*
+                * If we are at an unsupported band and have more bands
+                * left to scan, advance to the next supported one.
+                */
+               while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
+                       local->scan_band++;
+                       sband = local->hw.wiphy->bands[local->scan_band];
+                       local->scan_channel_idx = 0;
+               }
+
+               /* if no more bands/channels left, complete scan */
+               if (!sband || local->scan_channel_idx >= sband->n_channels) {
                        ieee80211_scan_completed(local_to_hw(local));
                        return;
                }
-               skip = !(local->enabled_modes & (1 << mode->mode));
-               chan = &mode->channels[local->scan_channel_idx];
-               if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
-                   (sdata->type == IEEE80211_IF_TYPE_IBSS &&
-                    !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
-                   (local->hw_modes & local->enabled_modes &
-                    (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+               skip = 0;
+               chan = &sband->channels[local->scan_channel_idx];
+
+               if (chan->flags & IEEE80211_CHAN_DISABLED ||
+                   (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+                    chan->flags & IEEE80211_CHAN_NO_IBSS))
                        skip = 1;
 
                if (!skip) {
-#if 0
-                       printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
-                              dev->name, chan->chan, chan->freq);
-#endif
-
                        local->scan_channel = chan;
                        if (ieee80211_hw_config(local)) {
-                               printk(KERN_DEBUG "%s: failed to set channel "
-                                      "%d (%d MHz) for scan\n", dev->name,
-                                      chan->chan, chan->freq);
+                               printk(KERN_DEBUG "%s: failed to set freq to "
+                                      "%d MHz for scan\n", dev->name,
+                                      chan->center_freq);
                                skip = 1;
                        }
                }
 
+               /* advance state machine to next channel/band */
                local->scan_channel_idx++;
-               if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
-                       if (local->scan_hw_mode->list.next != &local->modes_list) {
-                               local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
-                                                                struct ieee80211_hw_mode,
-                                                                list);
-                               local->scan_channel_idx = 0;
-                       }
+               if (local->scan_channel_idx >= sband->n_channels) {
+                       /*
+                        * scan_band may end up == IEEE80211_NUM_BANDS, but
+                        * we'll catch that case above and complete the scan
+                        * if that is the case.
+                        */
+                       local->scan_band++;
+                       local->scan_channel_idx = 0;
                }
 
                if (skip)
@@ -2747,17 +3475,18 @@ void ieee80211_sta_scan_work(struct work_struct *work)
                local->scan_state = SCAN_SEND_PROBE;
                break;
        case SCAN_SEND_PROBE:
-               if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
-                       ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
-                                                local->scan_ssid_len);
-                       next_delay = IEEE80211_CHANNEL_TIME;
-               } else
-                       next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+               next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->scan_state = SCAN_SET_CHANNEL;
+
+               if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       break;
+               ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+                                        local->scan_ssid_len);
+               next_delay = IEEE80211_CHANNEL_TIME;
                break;
        }
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning)
                queue_delayed_work(local->hw.workqueue, &local->scan_work,
                                   next_delay);
 }
@@ -2789,7 +3518,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
          * ResultCode: SUCCESS, INVALID_PARAMETERS
         */
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
@@ -2797,15 +3526,15 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
        if (local->ops->hw_scan) {
                int rc = local->ops->hw_scan(local_to_hw(local),
-                                           ssid, ssid_len);
+                                            ssid, ssid_len);
                if (!rc) {
-                       local->sta_scanning = 1;
+                       local->sta_hw_scanning = 1;
                        local->scan_dev = dev;
                }
                return rc;
        }
 
-       local->sta_scanning = 1;
+       local->sta_sw_scanning = 1;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -2816,7 +3545,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
                        continue;
 
                netif_stop_queue(sdata->dev);
-               if (sdata->type == IEEE80211_IF_TYPE_STA &&
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
                        ieee80211_send_nullfunc(local, sdata, 1);
        }
@@ -2828,10 +3557,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
        } else
                local->scan_ssid_len = 0;
        local->scan_state = SCAN_SET_CHANNEL;
-       local->scan_hw_mode = list_entry(local->modes_list.next,
-                                        struct ieee80211_hw_mode,
-                                        list);
        local->scan_channel_idx = 0;
+       local->scan_band = IEEE80211_BAND_2GHZ;
        local->scan_dev = dev;
 
        netif_tx_lock_bh(local->mdev);
@@ -2857,15 +3584,18 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return ieee80211_sta_start_scan(dev, ssid, ssid_len);
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
        }
 
+       ifsta->scan_ssid_len = ssid_len;
+       if (ssid_len)
+               memcpy(ifsta->scan_ssid, ssid, ssid_len);
        set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
        queue_work(local->hw.workqueue, &ifsta->work);
        return 0;
@@ -2883,18 +3613,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
                       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
                return current_ev;
 
-       if (!(local->enabled_modes & (1 << bss->hw_mode)))
-               return current_ev;
-
-       if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY &&
-           !bss->wpa_ie && !bss->rsn_ie)
-               return current_ev;
-
-       if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID &&
-           (local->scan_ssid_len != bss->ssid_len ||
-            memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0))
-               return current_ev;
-
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -2922,12 +3640,15 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = bss->channel;
-       iwe.u.freq.e = 0;
+       iwe.u.freq.m = bss->freq;
+       iwe.u.freq.e = 6;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
-       iwe.u.freq.m = bss->freq * 100000;
-       iwe.u.freq.e = 1;
+
+       memset(&iwe, 0, sizeof(iwe));
+       iwe.cmd = SIOCGIWFREQ;
+       iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+       iwe.u.freq.e = 0;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
@@ -2998,34 +3719,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
                }
        }
 
-       do {
-               char *buf;
-
-               if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO))
-                       break;
-
-               buf = kmalloc(100, GFP_ATOMIC);
-               if (!buf)
-                       break;
-
-               memset(&iwe, 0, sizeof(iwe));
-               iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, "bcn_int=%d", bss->beacon_int);
-               iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 buf);
-
-               memset(&iwe, 0, sizeof(iwe));
-               iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, "capab=0x%04x", bss->capability);
-               iwe.u.data.length = strlen(buf);
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 buf);
-
-               kfree(buf);
-               break;
-       } while (0);
-
        return current_ev;
 }
 
@@ -3079,25 +3772,29 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
        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);
+       DECLARE_MAC_BUF(mac);
 
        /* TODO: Could consider removing the least recently used entry and
         * allow new one to be added. */
        if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: No room for a new IBSS STA "
-                              "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr));
+                              "entry %s\n", dev->name, print_mac(mac, addr));
                }
                return NULL;
        }
 
-       printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), MAC_ARG(addr), dev->name);
+       printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
+              wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
 
        sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
        if (!sta)
                return NULL;
 
-       sta->supp_rates = sdata->u.sta.supp_rates_bits;
+       sta->flags |= WLAN_STA_AUTHORIZED;
+
+       sta->supp_rates[local->hw.conf.channel->band] =
+               sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
 
        rate_control_rate_init(sta, local);
 
@@ -3113,8 +3810,8 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
        printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
               dev->name, reason);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return -EINVAL;
 
        ieee80211_send_deauth(dev, ifsta, reason);
@@ -3131,7 +3828,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
        printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
               dev->name, reason);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return -EINVAL;
 
        if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
index d9ab0871fe7d2368f0579825b94ac04b537799e9..ed57fb8e82fc13ab9052fb4992524c572b1d2c6e 100644 (file)
@@ -49,8 +49,8 @@ static const u8 *get_mac_for_key(struct ieee80211_key *key)
         * 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))
+           (key->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+            key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN))
                addr = zero_addr;
 
        if (key->sta)
@@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
        const u8 *addr;
        int ret;
+       DECLARE_MAC_BUF(mac);
 
        if (!key->local->ops->set_key)
                return;
@@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
                printk(KERN_ERR "mac80211-%s: failed to set key "
-                      "(%d, " MAC_FMT ") to hardware (%d)\n",
+                      "(%d, %s) to hardware (%d)\n",
                       wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, MAC_ARG(addr), ret);
+                      key->conf.keyidx, print_mac(mac, addr), ret);
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 {
        const u8 *addr;
        int ret;
+       DECLARE_MAC_BUF(mac);
 
        if (!key->local->ops->set_key)
                return;
@@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 
        if (ret)
                printk(KERN_ERR "mac80211-%s: failed to remove key "
-                      "(%d, " MAC_FMT ") from hardware (%d)\n",
+                      "(%d, %s) from hardware (%d)\n",
                       wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, MAC_ARG(addr), ret);
+                      key->conf.keyidx, print_mac(mac, addr), ret);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
@@ -170,7 +172,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
                if (sta->flags & WLAN_STA_WME)
                        key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
        } else {
-               if (sdata->type == IEEE80211_IF_TYPE_STA) {
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
                        struct sta_info *ap;
 
                        /* same here, the AP could be using QoS */
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid.h b/package/mac80211/src/net/mac80211/rc80211_pid.h
new file mode 100644 (file)
index 0000000..04afc13
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
+ *
+ * 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 RC80211_PID_H
+#define RC80211_PID_H
+
+/* Sampling period for measuring percentage of failed frames in ms. */
+#define RC_PID_INTERVAL                        125
+
+/* Exponential averaging smoothness (used for I part of PID controller) */
+#define RC_PID_SMOOTHING_SHIFT         3
+#define RC_PID_SMOOTHING               (1 << RC_PID_SMOOTHING_SHIFT)
+
+/* Sharpening factor (used for D part of PID controller) */
+#define RC_PID_SHARPENING_FACTOR       0
+#define RC_PID_SHARPENING_DURATION     0
+
+/* Fixed point arithmetic shifting amount. */
+#define RC_PID_ARITH_SHIFT             8
+
+/* Fixed point arithmetic factor. */
+#define RC_PID_ARITH_FACTOR            (1 << RC_PID_ARITH_SHIFT)
+
+/* Proportional PID component coefficient. */
+#define RC_PID_COEFF_P                 15
+/* Integral PID component coefficient. */
+#define RC_PID_COEFF_I                 9
+/* Derivative PID component coefficient. */
+#define RC_PID_COEFF_D                 15
+
+/* Target failed frames rate for the PID controller. NB: This effectively gives
+ * maximum failed frames percentage we're willing to accept. If the wireless
+ * link quality is good, the controller will fail to adjust failed frames
+ * percentage to the target. This is intentional.
+ */
+#define RC_PID_TARGET_PF               14
+
+/* Rate behaviour normalization quantity over time. */
+#define RC_PID_NORM_OFFSET             3
+
+/* Push high rates right after loading. */
+#define RC_PID_FAST_START              0
+
+/* Arithmetic right shift for positive and negative values for ISO C. */
+#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
+       (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
+
+enum rc_pid_event_type {
+       RC_PID_EVENT_TYPE_TX_STATUS,
+       RC_PID_EVENT_TYPE_RATE_CHANGE,
+       RC_PID_EVENT_TYPE_TX_RATE,
+       RC_PID_EVENT_TYPE_PF_SAMPLE,
+};
+
+union rc_pid_event_data {
+       /* RC_PID_EVENT_TX_STATUS */
+       struct {
+               struct ieee80211_tx_status tx_status;
+       };
+       /* RC_PID_EVENT_TYPE_RATE_CHANGE */
+       /* RC_PID_EVENT_TYPE_TX_RATE */
+       struct {
+               int index;
+               int rate;
+       };
+       /* RC_PID_EVENT_TYPE_PF_SAMPLE */
+       struct {
+               s32 pf_sample;
+               s32 prop_err;
+               s32 int_err;
+               s32 der_err;
+       };
+};
+
+struct rc_pid_event {
+       /* The time when the event occured */
+       unsigned long timestamp;
+
+       /* Event ID number */
+       unsigned int id;
+
+       /* Type of event */
+       enum rc_pid_event_type type;
+
+       /* type specific data */
+       union rc_pid_event_data data;
+};
+
+/* Size of the event ring buffer. */
+#define RC_PID_EVENT_RING_SIZE 32
+
+struct rc_pid_event_buffer {
+       /* Counter that generates event IDs */
+       unsigned int ev_count;
+
+       /* Ring buffer of events */
+       struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE];
+
+       /* Index to the entry in events_buf to be reused */
+       unsigned int next_entry;
+
+       /* Lock that guards against concurrent access to this buffer struct */
+       spinlock_t lock;
+
+       /* Wait queue for poll/select and blocking I/O */
+       wait_queue_head_t waitqueue;
+};
+
+struct rc_pid_events_file_info {
+       /* The event buffer we read */
+       struct rc_pid_event_buffer *events;
+
+       /* The entry we have should read next */
+       unsigned int next_entry;
+};
+
+/**
+ * struct rc_pid_debugfs_entries - tunable parameters
+ *
+ * Algorithm parameters, tunable via debugfs.
+ * @dir: the debugfs directory for a specific phy
+ * @target: target percentage for failed frames
+ * @sampling_period: error sampling interval in milliseconds
+ * @coeff_p: absolute value of the proportional coefficient
+ * @coeff_i: absolute value of the integral coefficient
+ * @coeff_d: absolute value of the derivative coefficient
+ * @smoothing_shift: absolute value of the integral smoothing factor (i.e.
+ *     amount of smoothing introduced by the exponential moving average)
+ * @sharpen_factor: absolute value of the derivative sharpening factor (i.e.
+ *     amount of emphasis given to the derivative term after low activity
+ *     events)
+ * @sharpen_duration: duration of the sharpening effect after the detected low
+ *     activity event, relative to sampling_period
+ * @norm_offset: amount of normalization periodically performed on the learnt
+ *     rate behaviour values (lower means we should trust more what we learnt
+ *     about behaviour of rates, higher means we should trust more the natural
+ *     ordering of rates)
+ * @fast_start: if Y, push high rates right after initialization
+ */
+struct rc_pid_debugfs_entries {
+       struct dentry *dir;
+       struct dentry *target;
+       struct dentry *sampling_period;
+       struct dentry *coeff_p;
+       struct dentry *coeff_i;
+       struct dentry *coeff_d;
+       struct dentry *smoothing_shift;
+       struct dentry *sharpen_factor;
+       struct dentry *sharpen_duration;
+       struct dentry *norm_offset;
+       struct dentry *fast_start;
+};
+
+void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
+                                            struct ieee80211_tx_status *stat);
+
+void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
+                                              int index, int rate);
+
+void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
+                                          int index, int rate);
+
+void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
+                                            s32 pf_sample, s32 prop_err,
+                                            s32 int_err, s32 der_err);
+
+void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
+                                            struct dentry *dir);
+
+void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta);
+
+struct rc_pid_sta_info {
+       unsigned long last_change;
+       unsigned long last_sample;
+
+       u32 tx_num_failed;
+       u32 tx_num_xmit;
+
+       /* Average failed frames percentage error (i.e. actual vs. target
+        * percentage), scaled by RC_PID_SMOOTHING. This value is computed
+        * using using an exponential weighted average technique:
+        *
+        *           (RC_PID_SMOOTHING - 1) * err_avg_old + err
+        * err_avg = ------------------------------------------
+        *                       RC_PID_SMOOTHING
+        *
+        * where err_avg is the new approximation, err_avg_old the previous one
+        * and err is the error w.r.t. to the current failed frames percentage
+        * sample. Note that the bigger RC_PID_SMOOTHING the more weight is
+        * given to the previous estimate, resulting in smoother behavior (i.e.
+        * corresponding to a longer integration window).
+        *
+        * For computation, we actually don't use the above formula, but this
+        * one:
+        *
+        * err_avg_scaled = err_avg_old_scaled - err_avg_old + err
+        *
+        * where:
+        *      err_avg_scaled = err * RC_PID_SMOOTHING
+        *      err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
+        *
+        * This avoids floating point numbers and the per_failed_old value can
+        * easily be obtained by shifting per_failed_old_scaled right by
+        * RC_PID_SMOOTHING_SHIFT.
+        */
+       s32 err_avg_sc;
+
+       /* Last framed failes percentage sample. */
+       u32 last_pf;
+
+       /* Sharpening needed. */
+       u8 sharp_cnt;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* Event buffer */
+       struct rc_pid_event_buffer events;
+
+       /* Events debugfs file entry */
+       struct dentry *events_entry;
+#endif
+};
+
+/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
+ * be tuned individually for each interface.
+ */
+struct rc_pid_rateinfo {
+
+       /* Map sorted rates to rates in ieee80211_hw_mode. */
+       int index;
+
+       /* Map rates in ieee80211_hw_mode to sorted rates. */
+       int rev_index;
+
+       /* Did we do any measurement on this rate? */
+       bool valid;
+
+       /* Comparison with the lowest rate. */
+       int diff;
+};
+
+struct rc_pid_info {
+
+       /* The failed frames percentage target. */
+       unsigned int target;
+
+       /* Rate at which failed frames percentage is sampled in 0.001s. */
+       unsigned int sampling_period;
+
+       /* P, I and D coefficients. */
+       int coeff_p;
+       int coeff_i;
+       int coeff_d;
+
+       /* Exponential averaging shift. */
+       unsigned int smoothing_shift;
+
+       /* Sharpening factor and duration. */
+       unsigned int sharpen_factor;
+       unsigned int sharpen_duration;
+
+       /* Normalization offset. */
+       unsigned int norm_offset;
+
+       /* Fast starst parameter. */
+       unsigned int fast_start;
+
+       /* Rates information. */
+       struct rc_pid_rateinfo *rinfo;
+
+       /* Index of the last used rate. */
+       int oldrate;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* Debugfs entries created for the parameters above. */
+       struct rc_pid_debugfs_entries dentries;
+#endif
+};
+
+#endif /* RC80211_PID_H */
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_algo.c b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c
new file mode 100644 (file)
index 0000000..da8462b
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
+ *
+ * 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/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <net/mac80211.h>
+#include "ieee80211_rate.h"
+
+#include "rc80211_pid.h"
+
+
+/* This is an implementation of a TX rate control algorithm that uses a PID
+ * controller. Given a target failed frames rate, the controller decides about
+ * TX rate changes to meet the target failed frames rate.
+ *
+ * The controller basically computes the following:
+ *
+ * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening)
+ *
+ * where
+ *     adj     adjustment value that is used to switch TX rate (see below)
+ *     err     current error: target vs. current failed frames percentage
+ *     last_err        last error
+ *     err_avg average (i.e. poor man's integral) of recent errors
+ *     sharpening      non-zero when fast response is needed (i.e. right after
+ *                     association or no frames sent for a long time), heading
+ *                     to zero over time
+ *     CP      Proportional coefficient
+ *     CI      Integral coefficient
+ *     CD      Derivative coefficient
+ *
+ * CP, CI, CD are subject to careful tuning.
+ *
+ * The integral component uses a exponential moving average approach instead of
+ * an actual sliding window. The advantage is that we don't need to keep an
+ * array of the last N error values and computation is easier.
+ *
+ * Once we have the adj value, we map it to a rate by means of a learning
+ * algorithm. This algorithm keeps the state of the percentual failed frames
+ * difference between rates. The behaviour of the lowest available rate is kept
+ * as a reference value, and every time we switch between two rates, we compute
+ * the difference between the failed frames each rate exhibited. By doing so,
+ * we compare behaviours which different rates exhibited in adjacent timeslices,
+ * thus the comparison is minimally affected by external conditions. This
+ * difference gets propagated to the whole set of measurements, so that the
+ * reference is always the same. Periodically, we normalize this set so that
+ * recent events weigh the most. By comparing the adj value with this set, we
+ * avoid pejorative switches to lower rates and allow for switches to higher
+ * rates if they behaved well.
+ *
+ * Note that for the computations we use a fixed-point representation to avoid
+ * floating point arithmetic. Hence, all values are shifted left by
+ * RC_PID_ARITH_SHIFT.
+ */
+
+
+/* Adjust the rate while ensuring that we won't switch to a lower rate if it
+ * exhibited a worse failed frames behaviour and we'll choose the highest rate
+ * whose failed frames behaviour is not worse than the one of the original rate
+ * target. While at it, check that the new rate is valid. */
+static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
+                                        struct sta_info *sta, int adj,
+                                        struct rc_pid_rateinfo *rinfo)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_supported_band *sband;
+       int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+       int cur = sta->txrate_idx;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       band = sband->band;
+       n_bitrates = sband->n_bitrates;
+
+       /* Map passed arguments to sorted values. */
+       cur_sorted = rinfo[cur].rev_index;
+       new_sorted = cur_sorted + adj;
+
+       /* Check limits. */
+       if (new_sorted < 0)
+               new_sorted = rinfo[0].rev_index;
+       else if (new_sorted >= n_bitrates)
+               new_sorted = rinfo[n_bitrates - 1].rev_index;
+
+       tmp = new_sorted;
+
+       if (adj < 0) {
+               /* Ensure that the rate decrease isn't disadvantageous. */
+               for (probe = cur_sorted; probe >= new_sorted; probe--)
+                       if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
+                           rate_supported(sta, band, rinfo[probe].index))
+                               tmp = probe;
+       } else {
+               /* Look for rate increase with zero (or below) cost. */
+               for (probe = new_sorted + 1; probe < n_bitrates; probe++)
+                       if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
+                           rate_supported(sta, band, rinfo[probe].index))
+                               tmp = probe;
+       }
+
+       /* Fit the rate found to the nearest supported rate. */
+       do {
+               if (rate_supported(sta, band, rinfo[tmp].index)) {
+                       sta->txrate_idx = rinfo[tmp].index;
+                       break;
+               }
+               if (adj < 0)
+                       tmp--;
+               else
+                       tmp++;
+       } while (tmp < n_bitrates && tmp >= 0);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       rate_control_pid_event_rate_change(
+               &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
+               sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
+#endif
+}
+
+/* Normalize the failed frames per-rate differences. */
+static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l)
+{
+       int i, norm_offset = pinfo->norm_offset;
+       struct rc_pid_rateinfo *r = pinfo->rinfo;
+
+       if (r[0].diff > norm_offset)
+               r[0].diff -= norm_offset;
+       else if (r[0].diff < -norm_offset)
+               r[0].diff += norm_offset;
+       for (i = 0; i < l - 1; i++)
+               if (r[i + 1].diff > r[i].diff + norm_offset)
+                       r[i + 1].diff -= norm_offset;
+               else if (r[i + 1].diff <= r[i].diff)
+                       r[i + 1].diff += norm_offset;
+}
+
+static void rate_control_pid_sample(struct rc_pid_info *pinfo,
+                                   struct ieee80211_local *local,
+                                   struct sta_info *sta)
+{
+       struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
+       struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
+       struct ieee80211_supported_band *sband;
+       u32 pf;
+       s32 err_avg;
+       u32 err_prop;
+       u32 err_int;
+       u32 err_der;
+       int adj, i, j, tmp;
+       unsigned long period;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       spinfo = sta->rate_ctrl_priv;
+
+       /* In case nothing happened during the previous control interval, turn
+        * the sharpening factor on. */
+       period = (HZ * pinfo->sampling_period + 500) / 1000;
+       if (!period)
+               period = 1;
+       if (jiffies - spinfo->last_sample > 2 * period)
+               spinfo->sharp_cnt = pinfo->sharpen_duration;
+
+       spinfo->last_sample = jiffies;
+
+       /* This should never happen, but in case, we assume the old sample is
+        * still a good measurement and copy it. */
+       if (unlikely(spinfo->tx_num_xmit == 0))
+               pf = spinfo->last_pf;
+       else {
+               pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+               pf <<= RC_PID_ARITH_SHIFT;
+       }
+
+       spinfo->tx_num_xmit = 0;
+       spinfo->tx_num_failed = 0;
+
+       /* If we just switched rate, update the rate behaviour info. */
+       if (pinfo->oldrate != sta->txrate_idx) {
+
+               i = rinfo[pinfo->oldrate].rev_index;
+               j = rinfo[sta->txrate_idx].rev_index;
+
+               tmp = (pf - spinfo->last_pf);
+               tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
+
+               rinfo[j].diff = rinfo[i].diff + tmp;
+               pinfo->oldrate = sta->txrate_idx;
+       }
+       rate_control_pid_normalize(pinfo, sband->n_bitrates);
+
+       /* Compute the proportional, integral and derivative errors. */
+       err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf;
+
+       err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift;
+       spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop;
+       err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift;
+
+       err_der = (pf - spinfo->last_pf) *
+                 (1 + pinfo->sharpen_factor * spinfo->sharp_cnt);
+       spinfo->last_pf = pf;
+       if (spinfo->sharp_cnt)
+                       spinfo->sharp_cnt--;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int,
+                                        err_der);
+#endif
+
+       /* Compute the controller output. */
+       adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i
+             + err_der * pinfo->coeff_d);
+       adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT);
+
+       /* Change rate. */
+       if (adj)
+               rate_control_pid_adjust_rate(local, sta, adj, rinfo);
+}
+
+static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
+                                      struct sk_buff *skb,
+                                      struct ieee80211_tx_status *status)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_sub_if_data *sdata;
+       struct rc_pid_info *pinfo = priv;
+       struct sta_info *sta;
+       struct rc_pid_sta_info *spinfo;
+       unsigned long period;
+       struct ieee80211_supported_band *sband;
+
+       sta = sta_info_get(local, hdr->addr1);
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       if (!sta)
+               return;
+
+       /* Don't update the state if we're not controlling the rate. */
+       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+       if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+               sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+               return;
+       }
+
+       /* Ignore all frames that were sent with a different rate than the rate
+        * we currently advise mac80211 to use. */
+       if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+               goto ignore;
+
+       spinfo = sta->rate_ctrl_priv;
+       spinfo->tx_num_xmit++;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       rate_control_pid_event_tx_status(&spinfo->events, status);
+#endif
+
+       /* We count frames that totally failed to be transmitted as two bad
+        * frames, those that made it out but had some retries as one good and
+        * one bad frame. */
+       if (status->excessive_retries) {
+               spinfo->tx_num_failed += 2;
+               spinfo->tx_num_xmit++;
+       } else if (status->retry_count) {
+               spinfo->tx_num_failed++;
+               spinfo->tx_num_xmit++;
+       }
+
+       if (status->excessive_retries) {
+               sta->tx_retry_failed++;
+               sta->tx_num_consecutive_failures++;
+               sta->tx_num_mpdu_fail++;
+       } else {
+               sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
+               sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
+               sta->last_ack_rssi[2] = status->ack_signal;
+               sta->tx_num_consecutive_failures = 0;
+               sta->tx_num_mpdu_ok++;
+       }
+       sta->tx_retry_count += status->retry_count;
+       sta->tx_num_mpdu_fail += status->retry_count;
+
+       /* Update PID controller state. */
+       period = (HZ * pinfo->sampling_period + 500) / 1000;
+       if (!period)
+               period = 1;
+       if (time_after(jiffies, spinfo->last_sample + period))
+               rate_control_pid_sample(pinfo, local, sta);
+
+ignore:
+       sta_info_put(sta);
+}
+
+static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
+                                     struct ieee80211_supported_band *sband,
+                                     struct sk_buff *skb,
+                                     struct rate_selection *sel)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
+       int rateidx;
+       u16 fc;
+
+       sta = sta_info_get(local, hdr->addr1);
+
+       /* Send management frames and broadcast/multicast data using lowest
+        * rate. */
+       fc = le16_to_cpu(hdr->frame_control);
+       if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+           is_multicast_ether_addr(hdr->addr1) || !sta) {
+               sel->rate = rate_lowest(local, sband, sta);
+               if (sta)
+                       sta_info_put(sta);
+               return;
+       }
+
+       /* If a forced rate is in effect, select it. */
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+               sta->txrate_idx = sdata->bss->force_unicast_rateidx;
+
+       rateidx = sta->txrate_idx;
+
+       if (rateidx >= sband->n_bitrates)
+               rateidx = sband->n_bitrates - 1;
+
+       sta->last_txrate_idx = rateidx;
+
+       sta_info_put(sta);
+
+       sel->rate = &sband->bitrates[rateidx];
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       rate_control_pid_event_tx_rate(
+               &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
+               rateidx, sband->bitrates[rateidx].bitrate);
+#endif
+}
+
+static void rate_control_pid_rate_init(void *priv, void *priv_sta,
+                                         struct ieee80211_local *local,
+                                         struct sta_info *sta)
+{
+       /* TODO: This routine should consider using RSSI from previous packets
+        * as we need to have IEEE 802.1X auth succeed immediately after assoc..
+        * Until that method is implemented, we will use the lowest supported
+        * rate as a workaround. */
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       sta->txrate_idx = rate_lowest_index(local, sband, sta);
+}
+
+static void *rate_control_pid_alloc(struct ieee80211_local *local)
+{
+       struct rc_pid_info *pinfo;
+       struct rc_pid_rateinfo *rinfo;
+       struct ieee80211_supported_band *sband;
+       int i, j, tmp;
+       bool s;
+#ifdef CONFIG_MAC80211_DEBUGFS
+       struct rc_pid_debugfs_entries *de;
+#endif
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
+       if (!pinfo)
+               return NULL;
+
+       /* We can safely assume that sband won't change unless we get
+        * reinitialized. */
+       rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
+       if (!rinfo) {
+               kfree(pinfo);
+               return NULL;
+       }
+
+       /* Sort the rates. This is optimized for the most common case (i.e.
+        * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
+        * mapping too. */
+       for (i = 0; i < sband->n_bitrates; i++) {
+               rinfo[i].index = i;
+               rinfo[i].rev_index = i;
+               if (pinfo->fast_start)
+                       rinfo[i].diff = 0;
+               else
+                       rinfo[i].diff = i * pinfo->norm_offset;
+       }
+       for (i = 1; i < sband->n_bitrates; i++) {
+               s = 0;
+               for (j = 0; j < sband->n_bitrates - i; j++)
+                       if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
+                                    sband->bitrates[rinfo[j + 1].index].bitrate)) {
+                               tmp = rinfo[j].index;
+                               rinfo[j].index = rinfo[j + 1].index;
+                               rinfo[j + 1].index = tmp;
+                               rinfo[rinfo[j].index].rev_index = j;
+                               rinfo[rinfo[j + 1].index].rev_index = j + 1;
+                               s = 1;
+                       }
+               if (!s)
+                       break;
+       }
+
+       pinfo->target = RC_PID_TARGET_PF;
+       pinfo->sampling_period = RC_PID_INTERVAL;
+       pinfo->coeff_p = RC_PID_COEFF_P;
+       pinfo->coeff_i = RC_PID_COEFF_I;
+       pinfo->coeff_d = RC_PID_COEFF_D;
+       pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
+       pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
+       pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
+       pinfo->norm_offset = RC_PID_NORM_OFFSET;
+       pinfo->fast_start = RC_PID_FAST_START;
+       pinfo->rinfo = rinfo;
+       pinfo->oldrate = 0;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       de = &pinfo->dentries;
+       de->dir = debugfs_create_dir("rc80211_pid",
+                                    local->hw.wiphy->debugfsdir);
+       de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
+                                       de->dir, &pinfo->target);
+       de->sampling_period = debugfs_create_u32("sampling_period",
+                                                S_IRUSR | S_IWUSR, de->dir,
+                                                &pinfo->sampling_period);
+       de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
+                                        de->dir, &pinfo->coeff_p);
+       de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
+                                        de->dir, &pinfo->coeff_i);
+       de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
+                                        de->dir, &pinfo->coeff_d);
+       de->smoothing_shift = debugfs_create_u32("smoothing_shift",
+                                                S_IRUSR | S_IWUSR, de->dir,
+                                                &pinfo->smoothing_shift);
+       de->sharpen_factor = debugfs_create_u32("sharpen_factor",
+                                              S_IRUSR | S_IWUSR, de->dir,
+                                              &pinfo->sharpen_factor);
+       de->sharpen_duration = debugfs_create_u32("sharpen_duration",
+                                                 S_IRUSR | S_IWUSR, de->dir,
+                                                 &pinfo->sharpen_duration);
+       de->norm_offset = debugfs_create_u32("norm_offset",
+                                            S_IRUSR | S_IWUSR, de->dir,
+                                            &pinfo->norm_offset);
+       de->fast_start = debugfs_create_bool("fast_start",
+                                            S_IRUSR | S_IWUSR, de->dir,
+                                            &pinfo->fast_start);
+#endif
+
+       return pinfo;
+}
+
+static void rate_control_pid_free(void *priv)
+{
+       struct rc_pid_info *pinfo = priv;
+#ifdef CONFIG_MAC80211_DEBUGFS
+       struct rc_pid_debugfs_entries *de = &pinfo->dentries;
+
+       debugfs_remove(de->fast_start);
+       debugfs_remove(de->norm_offset);
+       debugfs_remove(de->sharpen_duration);
+       debugfs_remove(de->sharpen_factor);
+       debugfs_remove(de->smoothing_shift);
+       debugfs_remove(de->coeff_d);
+       debugfs_remove(de->coeff_i);
+       debugfs_remove(de->coeff_p);
+       debugfs_remove(de->sampling_period);
+       debugfs_remove(de->target);
+       debugfs_remove(de->dir);
+#endif
+
+       kfree(pinfo->rinfo);
+       kfree(pinfo);
+}
+
+static void rate_control_pid_clear(void *priv)
+{
+}
+
+static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
+{
+       struct rc_pid_sta_info *spinfo;
+
+       spinfo = kzalloc(sizeof(*spinfo), gfp);
+       if (spinfo == NULL)
+               return NULL;
+
+       spinfo->last_sample = jiffies;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       spin_lock_init(&spinfo->events.lock);
+       init_waitqueue_head(&spinfo->events.waitqueue);
+#endif
+
+       return spinfo;
+}
+
+static void rate_control_pid_free_sta(void *priv, void *priv_sta)
+{
+       struct rc_pid_sta_info *spinfo = priv_sta;
+       kfree(spinfo);
+}
+
+static struct rate_control_ops mac80211_rcpid = {
+       .name = "pid",
+       .tx_status = rate_control_pid_tx_status,
+       .get_rate = rate_control_pid_get_rate,
+       .rate_init = rate_control_pid_rate_init,
+       .clear = rate_control_pid_clear,
+       .alloc = rate_control_pid_alloc,
+       .free = rate_control_pid_free,
+       .alloc_sta = rate_control_pid_alloc_sta,
+       .free_sta = rate_control_pid_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+       .add_sta_debugfs = rate_control_pid_add_sta_debugfs,
+       .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs,
+#endif
+};
+
+MODULE_DESCRIPTION("PID controller based rate control algorithm");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Mattias Nissler");
+MODULE_LICENSE("GPL");
+
+int __init rc80211_pid_init(void)
+{
+       return ieee80211_rate_control_register(&mac80211_rcpid);
+}
+
+void rc80211_pid_exit(void)
+{
+       ieee80211_rate_control_unregister(&mac80211_rcpid);
+}
+
+#ifdef CONFIG_MAC80211_RC_PID_MODULE
+module_init(rc80211_pid_init);
+module_exit(rc80211_pid_exit);
+#endif
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
new file mode 100644 (file)
index 0000000..88b8dc9
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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/spinlock.h>
+#include <linux/poll.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_rate.h"
+
+#include "rc80211_pid.h"
+
+static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
+                                  enum rc_pid_event_type type,
+                                  union rc_pid_event_data *data)
+{
+       struct rc_pid_event *ev;
+       unsigned long status;
+
+       spin_lock_irqsave(&buf->lock, status);
+       ev = &(buf->ring[buf->next_entry]);
+       buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE;
+
+       ev->timestamp = jiffies;
+       ev->id = buf->ev_count++;
+       ev->type = type;
+       ev->data = *data;
+
+       spin_unlock_irqrestore(&buf->lock, status);
+
+       wake_up_all(&buf->waitqueue);
+}
+
+void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
+                                            struct ieee80211_tx_status *stat)
+{
+       union rc_pid_event_data evd;
+
+       memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
+       rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
+}
+
+void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
+                                              int index, int rate)
+{
+       union rc_pid_event_data evd;
+
+       evd.index = index;
+       evd.rate = rate;
+       rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd);
+}
+
+void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
+                                          int index, int rate)
+{
+       union rc_pid_event_data evd;
+
+       evd.index = index;
+       evd.rate = rate;
+       rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd);
+}
+
+void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
+                                            s32 pf_sample, s32 prop_err,
+                                            s32 int_err, s32 der_err)
+{
+       union rc_pid_event_data evd;
+
+       evd.pf_sample = pf_sample;
+       evd.prop_err = prop_err;
+       evd.int_err = int_err;
+       evd.der_err = der_err;
+       rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd);
+}
+
+static int rate_control_pid_events_open(struct inode *inode, struct file *file)
+{
+       struct rc_pid_sta_info *sinfo = inode->i_private;
+       struct rc_pid_event_buffer *events = &sinfo->events;
+       struct rc_pid_events_file_info *file_info;
+       unsigned int status;
+
+       /* Allocate a state struct */
+       file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
+       if (file_info == NULL)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&events->lock, status);
+
+       file_info->next_entry = events->next_entry;
+       file_info->events = events;
+
+       spin_unlock_irqrestore(&events->lock, status);
+
+       file->private_data = file_info;
+
+       return 0;
+}
+
+static int rate_control_pid_events_release(struct inode *inode,
+                                          struct file *file)
+{
+       struct rc_pid_events_file_info *file_info = file->private_data;
+
+       kfree(file_info);
+
+       return 0;
+}
+
+static unsigned int rate_control_pid_events_poll(struct file *file,
+                                                poll_table *wait)
+{
+       struct rc_pid_events_file_info *file_info = file->private_data;
+
+       poll_wait(file, &file_info->events->waitqueue, wait);
+
+       return POLLIN | POLLRDNORM;
+}
+
+#define RC_PID_PRINT_BUF_SIZE 64
+
+static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
+                                           size_t length, loff_t *offset)
+{
+       struct rc_pid_events_file_info *file_info = file->private_data;
+       struct rc_pid_event_buffer *events = file_info->events;
+       struct rc_pid_event *ev;
+       char pb[RC_PID_PRINT_BUF_SIZE];
+       int ret;
+       int p;
+       unsigned int status;
+
+       /* Check if there is something to read. */
+       if (events->next_entry == file_info->next_entry) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               /* Wait */
+               ret = wait_event_interruptible(events->waitqueue,
+                               events->next_entry != file_info->next_entry);
+
+               if (ret)
+                       return ret;
+       }
+
+       /* Write out one event per call. I don't care whether it's a little
+        * inefficient, this is debugging code anyway. */
+       spin_lock_irqsave(&events->lock, status);
+
+       /* Get an event */
+       ev = &(events->ring[file_info->next_entry]);
+       file_info->next_entry = (file_info->next_entry + 1) %
+                               RC_PID_EVENT_RING_SIZE;
+
+       /* Print information about the event. Note that userpace needs to
+        * provide large enough buffers. */
+       length = length < RC_PID_PRINT_BUF_SIZE ?
+                length : RC_PID_PRINT_BUF_SIZE;
+       p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
+       switch (ev->type) {
+       case RC_PID_EVENT_TYPE_TX_STATUS:
+               p += snprintf(pb + p, length - p, "tx_status %u %u",
+                             ev->data.tx_status.excessive_retries,
+                             ev->data.tx_status.retry_count);
+               break;
+       case RC_PID_EVENT_TYPE_RATE_CHANGE:
+               p += snprintf(pb + p, length - p, "rate_change %d %d",
+                             ev->data.index, ev->data.rate);
+               break;
+       case RC_PID_EVENT_TYPE_TX_RATE:
+               p += snprintf(pb + p, length - p, "tx_rate %d %d",
+                             ev->data.index, ev->data.rate);
+               break;
+       case RC_PID_EVENT_TYPE_PF_SAMPLE:
+               p += snprintf(pb + p, length - p,
+                             "pf_sample %d %d %d %d",
+                             ev->data.pf_sample, ev->data.prop_err,
+                             ev->data.int_err, ev->data.der_err);
+               break;
+       }
+       p += snprintf(pb + p, length - p, "\n");
+
+       spin_unlock_irqrestore(&events->lock, status);
+
+       if (copy_to_user(buf, pb, p))
+               return -EFAULT;
+
+       return p;
+}
+
+#undef RC_PID_PRINT_BUF_SIZE
+
+static struct file_operations rc_pid_fop_events = {
+       .owner = THIS_MODULE,
+       .read = rate_control_pid_events_read,
+       .poll = rate_control_pid_events_poll,
+       .open = rate_control_pid_events_open,
+       .release = rate_control_pid_events_release,
+};
+
+void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
+                                            struct dentry *dir)
+{
+       struct rc_pid_sta_info *spinfo = priv_sta;
+
+       spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO,
+                                                  dir, spinfo,
+                                                  &rc_pid_fop_events);
+}
+
+void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+       struct rc_pid_sta_info *spinfo = priv_sta;
+
+       debugfs_remove(spinfo->events_entry);
+}
index ef91ce428acaafaede5a9d0fd6f3609984152c59..c4678905a1421ed0e359e61022d53b7d95a4f74d 100644 (file)
@@ -7,13 +7,13 @@
  * 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 <linux/module.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 /* This is a minimal implementation of TX rate controlling that can be used
  * as the default when no improved mechanisms are available. */
 
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP   15
 
 #define RATE_CONTROL_EMERG_DEC 2
 #define RATE_CONTROL_INTERVAL (HZ / 20)
 #define RATE_CONTROL_MIN_TX 10
 
-MODULE_ALIAS("rc80211_default");
-
 static void rate_control_rate_inc(struct ieee80211_local *local,
                                  struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_hw_mode *mode;
-       int i = sta->txrate;
+       struct ieee80211_supported_band *sband;
+       int i = sta->txrate_idx;
        int maxrate;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
@@ -45,18 +45,17 @@ static void rate_control_rate_inc(struct ieee80211_local *local,
                return;
        }
 
-       mode = local->oper_hw_mode;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
        maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
 
-       if (i > mode->num_rates)
-               i = mode->num_rates - 2;
+       if (i > sband->n_bitrates)
+               i = sband->n_bitrates - 2;
 
-       while (i + 1 < mode->num_rates) {
+       while (i + 1 < sband->n_bitrates) {
                i++;
-               if (sta->supp_rates & BIT(i) &&
-                   mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+               if (rate_supported(sta, sband->band, i) &&
                    (maxrate < 0 || i <= maxrate)) {
-                       sta->txrate = i;
+                       sta->txrate_idx = i;
                        break;
                }
        }
@@ -67,8 +66,8 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
                                  struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_hw_mode *mode;
-       int i = sta->txrate;
+       struct ieee80211_supported_band *sband;
+       int i = sta->txrate_idx;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
        if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
@@ -76,40 +75,19 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
                return;
        }
 
-       mode = local->oper_hw_mode;
-       if (i > mode->num_rates)
-               i = mode->num_rates;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       if (i > sband->n_bitrates)
+               i = sband->n_bitrates;
 
        while (i > 0) {
                i--;
-               if (sta->supp_rates & BIT(i) &&
-                   mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
-                       sta->txrate = i;
+               if (rate_supported(sta, sband->band, i)) {
+                       sta->txrate_idx = i;
                        break;
                }
        }
 }
 
-
-static struct ieee80211_rate *
-rate_control_lowest_rate(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];
-
-               if (rate->flags & IEEE80211_RATE_SUPPORTED)
-                       return rate;
-       }
-
-       printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
-              "found\n");
-       return &mode->rates[0];
-}
-
-
 struct global_rate_control {
        int dummy;
 };
@@ -188,7 +166,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
                } else if (per_failed < RATE_CONTROL_NUM_UP) {
                        rate_control_rate_inc(local, sta);
                }
-               srctrl->tx_avg_rate_sum += status->control.rate->rate;
+               srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate;
                srctrl->tx_avg_rate_num++;
                srctrl->tx_num_failures = 0;
                srctrl->tx_num_xmit = 0;
@@ -201,9 +179,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
                srctrl->avg_rate_update = jiffies;
                if (srctrl->tx_avg_rate_num > 0) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
+                       DECLARE_MAC_BUF(mac);
+                       printk(KERN_DEBUG "%s: STA %s Average rate: "
                               "%d (%d/%d)\n",
-                              dev->name, MAC_ARG(sta->addr),
+                              dev->name, print_mac(mac, sta->addr),
                               srctrl->tx_avg_rate_sum /
                               srctrl->tx_avg_rate_num,
                               srctrl->tx_avg_rate_sum,
@@ -218,56 +197,47 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
 }
 
 
-static struct ieee80211_rate *
+static void
 rate_control_simple_get_rate(void *priv, struct net_device *dev,
+                            struct ieee80211_supported_band *sband,
                             struct sk_buff *skb,
-                            struct rate_control_extra *extra)
+                            struct rate_selection *sel)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_hw_mode *mode = extra->mode;
+       struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
-       int rateidx, nonerp_idx;
+       int rateidx;
        u16 fc;
 
-       memset(extra, 0, sizeof(*extra));
+       sta = sta_info_get(local, hdr->addr1);
 
+       /* Send management frames and broadcast/multicast data using lowest
+        * rate. */
        fc = le16_to_cpu(hdr->frame_control);
        if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           (hdr->addr1[0] & 0x01)) {
-               /* Send management frames and broadcast/multicast data using
-                * lowest rate. */
-               /* TODO: this could probably be improved.. */
-               return rate_control_lowest_rate(local, mode);
+           is_multicast_ether_addr(hdr->addr1) || !sta) {
+               sel->rate = rate_lowest(local, sband, sta);
+               if (sta)
+                       sta_info_put(sta);
+               return;
        }
 
-       sta = sta_info_get(local, hdr->addr1);
-
-       if (!sta)
-               return rate_control_lowest_rate(local, mode);
-
+       /* If a forced rate is in effect, select it. */
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
-               sta->txrate = sdata->bss->force_unicast_rateidx;
+               sta->txrate_idx = sdata->bss->force_unicast_rateidx;
 
-       rateidx = sta->txrate;
+       rateidx = sta->txrate_idx;
 
-       if (rateidx >= mode->num_rates)
-               rateidx = mode->num_rates - 1;
+       if (rateidx >= sband->n_bitrates)
+               rateidx = sband->n_bitrates - 1;
 
-       sta->last_txrate = rateidx;
-       nonerp_idx = rateidx;
-       while (nonerp_idx > 0 &&
-              ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
-               !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
-               !(sta->supp_rates & BIT(nonerp_idx))))
-               nonerp_idx--;
-       extra->nonerp = &mode->rates[nonerp_idx];
+       sta->last_txrate_idx = rateidx;
 
        sta_info_put(sta);
 
-       return &mode->rates[rateidx];
+       sel->rate = &sband->bitrates[rateidx];
 }
 
 
@@ -275,21 +245,15 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta,
                                          struct ieee80211_local *local,
                                          struct sta_info *sta)
 {
-       struct ieee80211_hw_mode *mode;
-       int i;
-       sta->txrate = 0;
-       mode = local->oper_hw_mode;
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
        /* TODO: This routine should consider using RSSI from previous packets
         * as we need to have IEEE 802.1X auth succeed immediately after assoc..
         * Until that method is implemented, we will use the lowest supported rate
         * as a workaround, */
-       for (i = 0; i < mode->num_rates; i++) {
-               if ((sta->supp_rates & BIT(i)) &&
-                   (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) {
-                       sta->txrate = i;
-                       break;
-               }
-       }
+       sta->txrate_idx = rate_lowest_index(local, sband, sta);
 }
 
 
@@ -393,8 +357,7 @@ static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
 }
 #endif
 
-static struct rate_control_ops rate_control_simple = {
-       .module = THIS_MODULE,
+static struct rate_control_ops mac80211_rcsimple = {
        .name = "simple",
        .tx_status = rate_control_simple_tx_status,
        .get_rate = rate_control_simple_get_rate,
@@ -410,21 +373,20 @@ static struct rate_control_ops rate_control_simple = {
 #endif
 };
 
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simple rate control algorithm");
 
-static int __init rate_control_simple_init(void)
+int __init rc80211_simple_init(void)
 {
-       return ieee80211_rate_control_register(&rate_control_simple);
+       return ieee80211_rate_control_register(&mac80211_rcsimple);
 }
 
-
-static void __exit rate_control_simple_exit(void)
+void rc80211_simple_exit(void)
 {
-       ieee80211_rate_control_unregister(&rate_control_simple);
+       ieee80211_rate_control_unregister(&mac80211_rcsimple);
 }
 
-
-subsys_initcall(rate_control_simple_init);
-module_exit(rate_control_simple_exit);
-
-MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE
+module_init(rc80211_simple_init);
+module_exit(rc80211_simple_exit);
+#endif
diff --git a/package/mac80211/src/net/mac80211/regdomain.c b/package/mac80211/src/net/mac80211/regdomain.c
deleted file mode 100644 (file)
index f42678f..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, 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.
- */
-
-/*
- * This regulatory domain control implementation is known to be incomplete
- * and confusing. mac80211 regulatory domain control will be significantly
- * reworked in the not-too-distant future.
- *
- * For now, drivers wishing to control which channels are and aren't available
- * are advised as follows:
- *  - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
- *  - continue to include *ALL* possible channels in the modes registered
- *    through ieee80211_register_hwmode()
- *  - for each allowable ieee80211_channel structure registered in the above
- *    call, set the flag member to some meaningful value such as
- *    IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
- *    IEEE80211_CHAN_W_IBSS.
- *  - leave flag as 0 for non-allowable channels
- *
- * The usual implementation is for a driver to read a device EEPROM to
- * determine which regulatory domain it should be operating under, then
- * looking up the allowable channels in a driver-local table, then performing
- * the above.
- */
-
-#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);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
-
-struct ieee80211_channel_range {
-       short start_freq;
-       short end_freq;
-       unsigned char power_level;
-       unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
-       { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
-       { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
-       { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
-       { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
-       { 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
-       { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
-       { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
-       { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
-       { 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
-       ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
-{
-       int i;
-
-       chan->flag = 0;
-
-       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) {
-                       if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
-                           chan->freq >= 5260 && chan->freq <= 5320) {
-                               /*
-                                * Skip new channels in Japan since the
-                                * firmware was not marked having been upgraded
-                                * by the vendor.
-                                */
-                               continue;
-                       }
-
-                       if (ieee80211_regdom == 0x10 &&
-                           (chan->freq == 5190 || chan->freq == 5210 ||
-                            chan->freq == 5230)) {
-                                   /* Skip MKK channels when in FCC domain. */
-                                   continue;
-                       }
-
-                       chan->flag |= IEEE80211_CHAN_W_SCAN |
-                               IEEE80211_CHAN_W_ACTIVE_SCAN |
-                               IEEE80211_CHAN_W_IBSS;
-                       chan->power_level = r->power_level;
-                       chan->antenna_max = r->antenna_max;
-
-                       if (ieee80211_regdom == 64 &&
-                           (chan->freq == 5170 || chan->freq == 5190 ||
-                            chan->freq == 5210 || chan->freq == 5230)) {
-                               /*
-                                * New regulatory rules in Japan have backwards
-                                * compatibility with old channels in 5.15-5.25
-                                * GHz band, but the station is not allowed to
-                                * use active scan on these old channels.
-                                */
-                               chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
-                       }
-
-                       if (ieee80211_regdom == 64 &&
-                           (chan->freq == 5260 || chan->freq == 5280 ||
-                            chan->freq == 5300 || chan->freq == 5320)) {
-                               /*
-                                * IBSS is not allowed on 5.25-5.35 GHz band
-                                * due to radar detection requirements.
-                                */
-                               chan->flag &= ~IEEE80211_CHAN_W_IBSS;
-                       }
-
-                       break;
-               }
-       }
-}
-
-
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
-{
-       int c;
-       for (c = 0; c < mode->num_channels; c++)
-               ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
-}
-
-
-void ieee80211_regdomain_init(void)
-{
-       if (ieee80211_regdom == 0x40)
-               channel_range = ieee80211_mkk_channels;
-}
-
index 064924cb289bb3533bfcbd20763990fcd2e82839..943ba908298c3c1d07d0df56976b52064910f52a 100644 (file)
 #include "tkip.h"
 #include "wme.h"
 
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+                               struct tid_ampdu_rx *tid_agg_rx,
+                               struct sk_buff *skb, u16 mpdu_seq_num,
+                               int bar_req);
 /*
  * monitor mode reception
  *
@@ -61,8 +65,12 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
                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))
+       if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
+                       cpu_to_le16(IEEE80211_FTYPE_CTL)) &&
+           ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+                       cpu_to_le16(IEEE80211_STYPE_PSPOLL)) &&
+           ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+                       cpu_to_le16(IEEE80211_STYPE_BACK_REQ)))
                return 1;
        return 0;
 }
@@ -74,13 +82,14 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-                    struct ieee80211_rx_status *status)
+                    struct ieee80211_rx_status *status,
+                    struct ieee80211_rate *rate)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_rate *rate;
        int needed_headroom = 0;
-       struct ieee80211_rtap_hdr {
-               struct ieee80211_radiotap_header hdr;
+       struct ieee80211_radiotap_header *rthdr;
+       __le64 *rttsft = NULL;
+       struct ieee80211_rtap_fixed_data {
                u8 flags;
                u8 rate;
                __le16 chan_freq;
@@ -88,7 +97,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                u8 antsignal;
                u8 padding_for_rxflags;
                __le16 rx_flags;
-       } __attribute__ ((packed)) *rthdr;
+       } __attribute__ ((packed)) *rtfixed;
        struct sk_buff *skb, *skb2;
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
@@ -105,7 +114,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (status->flag & RX_FLAG_RADIOTAP)
                rtap_len = ieee80211_get_radiotap_len(origskb->data);
        else
-               needed_headroom = sizeof(*rthdr);
+               /* room for radiotap header, always present fields and TSFT */
+               needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
@@ -133,7 +143,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                 * them allocate enough headroom to start with.
                 */
                if (skb_headroom(skb) < needed_headroom &&
-                   pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+                   pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
                        dev_kfree_skb(skb);
                        return NULL;
                }
@@ -152,45 +162,56 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 
        /* if necessary, prepend radiotap information */
        if (!(status->flag & RX_FLAG_RADIOTAP)) {
+               rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
+               rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
+               if (status->flag & RX_FLAG_TSFT) {
+                       rttsft = (void *) skb_push(skb, sizeof(*rttsft));
+                       rtap_len += 8;
+               }
                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 =
+               memset(rtfixed, 0, sizeof(*rtfixed));
+               rthdr->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;
+               rtfixed->flags = 0;
+               if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+                       rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
+
+               if (rttsft) {
+                       *rttsft = cpu_to_le64(status->mactime);
+                       rthdr->it_present |=
+                               cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+               }
 
                /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
-               rthdr->rx_flags = 0;
+               rtfixed->rx_flags = 0;
                if (status->flag &
                    (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
-                       rthdr->rx_flags |=
+                       rtfixed->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;
+               rtfixed->rate = rate->bitrate / 5;
 
-               rthdr->chan_freq = cpu_to_le16(status->freq);
+               rtfixed->chan_freq = cpu_to_le16(status->freq);
 
-               if (status->phymode == MODE_IEEE80211A)
-                       rthdr->chan_flags =
+               if (status->band == IEEE80211_BAND_5GHZ)
+                       rtfixed->chan_flags =
                                cpu_to_le16(IEEE80211_CHAN_OFDM |
                                            IEEE80211_CHAN_5GHZ);
                else
-                       rthdr->chan_flags =
+                       rtfixed->chan_flags =
                                cpu_to_le16(IEEE80211_CHAN_DYN |
                                            IEEE80211_CHAN_2GHZ);
 
-               rthdr->antsignal = status->ssi;
+               rtfixed->antsignal = status->ssi;
+               rthdr->it_len = cpu_to_le16(rtap_len);
        }
 
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -199,7 +220,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->type != IEEE80211_IF_TYPE_MNTR)
+               if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
+                       continue;
+
+               if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
                        continue;
 
                if (prev_dev) {
@@ -225,15 +249,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *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)
+static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
 {
        u8 *data = rx->skb->data;
        int tid;
@@ -243,6 +259,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
                u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
                /* frame has qos control */
                tid = qc[0] & QOS_CONTROL_TID_MASK;
+               if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+                       rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+               else
+                       rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
        } else {
                if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
                        /* Separate TID for management frames */
@@ -262,40 +282,59 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
        /* 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;
+}
+
+static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx)
+{
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
+       int hdrlen;
 
-       return TXRX_CONTINUE;
+       if (!WLAN_FC_DATA_PRESENT(rx->fc))
+               return;
+
+       /*
+        * Drivers are required to align the payload data in a way that
+        * guarantees that the contained IP header is aligned to a four-
+        * byte boundary. In the case of regular frames, this simply means
+        * aligning the payload to a four-byte boundary (because either
+        * the IP header is directly contained, or IV/RFC1042 headers that
+        * have a length divisible by four are in front of it.
+        *
+        * With A-MSDU frames, however, the payload data address must
+        * yield two modulo four because there are 14-byte 802.3 headers
+        * within the A-MSDU frames that push the IP header further back
+        * to a multiple of four again. Thankfully, the specs were sane
+        * enough this time around to require padding each A-MSDU subframe
+        * to a length that is a multiple of four.
+        *
+        * Padding like atheros hardware adds which is inbetween the 802.11
+        * header and the payload is not supported, the driver is required
+        * to move the 802.11 header further back in that case.
+        */
+       hdrlen = ieee80211_get_hdrlen(rx->fc);
+       if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+               hdrlen += ETH_HLEN;
+       WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
+#endif
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+                                  struct sk_buff *skb,
+                                  struct ieee80211_rx_status *status,
+                                  struct ieee80211_rate *rate)
 {
-       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))
+       if (status->band == IEEE80211_BAND_5GHZ ||
+           (status->band == IEEE80211_BAND_5GHZ &&
+            rate->flags & IEEE80211_RATE_ERP_G))
                hdrtime = CHAN_UTIL_HDR_SHORT;
        else
                hdrtime = CHAN_UTIL_HDR_LONG;
@@ -304,55 +343,53 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
        if (!is_multicast_ether_addr(hdr->addr1))
                load += hdrtime;
 
-       load += skb->len * rate->rate_inv;
+       /* TODO: optimise again */
+       load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
        /* 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;
+       return load;
 }
 
-ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
-{
-       ieee80211_rx_h_parse_qos,
-       ieee80211_rx_h_load_stats,
-       NULL
-};
-
 /* rx handlers */
 
-static ieee80211_txrx_result
+static ieee80211_rx_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;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_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(local->sta_hw_scanning))
+               return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+
+       if (unlikely(local->sta_sw_scanning)) {
+               /* drop all the other packets during a software scan anyway */
+               if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+                   != RX_QUEUED)
+                       dev_kfree_skb(skb);
+               return RX_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 RX_DROP_UNUSABLE;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr;
@@ -367,28 +404,16 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
                                rx->local->dot11FrameDuplicateCount++;
                                rx->sta->num_duplicates++;
                        }
-                       return TXRX_DROP;
+                       return RX_DROP_MONITOR;
                } 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;
+               return RX_DROP_MONITOR;
        }
 
-       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.
         *
@@ -400,7 +425,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
        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->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
                     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
                if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
                     !(rx->fc & IEEE80211_FCTL_TODS) &&
@@ -408,23 +433,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
                    || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
                        /* Drop IBSS frames and frames for other hosts
                         * silently. */
-                       return TXRX_DROP;
+                       return RX_DROP_MONITOR;
                }
 
-               return TXRX_DROP;
+               return RX_DROP_MONITOR;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
 
-static ieee80211_txrx_result
+static ieee80211_rx_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;
+       ieee80211_rx_result result = RX_DROP_UNUSABLE;
        struct ieee80211_key *stakey = NULL;
 
        /*
@@ -454,14 +479,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
         */
 
        if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
-               return TXRX_CONTINUE;
+               return RX_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;
+               return RX_CONTINUE;
 
        if (rx->sta)
                stakey = rcu_dereference(rx->sta->key);
@@ -480,12 +505,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
                 */
                if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
                    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-                       return TXRX_CONTINUE;
+                       return RX_CONTINUE;
 
                hdrlen = ieee80211_get_hdrlen(rx->fc);
 
                if (rx->skb->len < 8 + hdrlen)
-                       return TXRX_DROP; /* TODO: count this? */
+                       return RX_DROP_UNUSABLE; /* TODO: count this? */
 
                /*
                 * no need to call ieee80211_wep_get_keyidx,
@@ -509,10 +534,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
+#ifdef CONFIG_MAC80211_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: RX protected frame,"
                               " but have no key\n", rx->dev->name);
-               return TXRX_DROP;
+#endif /* CONFIG_MAC80211_DEBUG */
+               return RX_DROP_MONITOR;
        }
 
        /* Check for weak IVs if possible */
@@ -544,6 +571,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata;
+       DECLARE_MAC_BUF(mac);
+
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 
        if (sdata->bss)
@@ -551,8 +580,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
        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);
+       printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
+              dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -563,6 +592,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        int sent = 0;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_tx_packet_data *pkt_data;
+       DECLARE_MAC_BUF(mac);
 
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
        if (sdata->bss)
@@ -576,8 +606,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
                        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);
+       printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
+              dev->name, print_mac(mac, 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) {
@@ -591,9 +621,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
                local->total_ps_buffered--;
                sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+               printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
                       "since STA not sleeping anymore\n", dev->name,
-                      MAC_ARG(sta->addr), sta->aid);
+                      print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
                dev_queue_xmit(skb);
@@ -602,7 +632,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        return sent;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 {
        struct sta_info *sta = rx->sta;
@@ -610,18 +640,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 
        if (!sta)
-               return TXRX_CONTINUE;
+               return RX_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 (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+                                               IEEE80211_IF_TYPE_IBSS);
                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) {
+           rx->sdata->vif.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.
@@ -630,7 +661,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
        }
 
        if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
@@ -657,10 +688,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
                 * as a dropped packed. */
                sta->rx_packets++;
                dev_kfree_skb(rx->skb);
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
 static inline struct ieee80211_fragment_entry *
@@ -680,13 +711,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_DEBUG
                struct ieee80211_hdr *hdr =
                        (struct ieee80211_hdr *) entry->skb_list.next->data;
+               DECLARE_MAC_BUF(mac);
+               DECLARE_MAC_BUF(mac2);
                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",
+                      "addr1=%s addr2=%s\n",
                       sdata->dev->name, idx,
                       jiffies - entry->first_frag_time, entry->seq,
-                      entry->last_frag, MAC_ARG(hdr->addr1),
-                      MAC_ARG(hdr->addr2));
+                      entry->last_frag, print_mac(mac, hdr->addr1),
+                      print_mac(mac2, hdr->addr2));
 #endif /* CONFIG_MAC80211_DEBUG */
                __skb_queue_purge(&entry->skb_list);
        }
@@ -744,7 +777,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
        return NULL;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr;
@@ -752,6 +785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
        unsigned int frag, seq;
        struct ieee80211_fragment_entry *entry;
        struct sk_buff *skb;
+       DECLARE_MAC_BUF(mac);
 
        hdr = (struct ieee80211_hdr *) rx->skb->data;
        sc = le16_to_cpu(hdr->seq_ctrl);
@@ -780,7 +814,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                               rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
                               CCMP_PN_LEN);
                }
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
        /* This is a fragment for a frame that should already be pending in
@@ -790,7 +824,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                                          rx->u.rx.queue, hdr);
        if (!entry) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-               return TXRX_DROP;
+               return RX_DROP_MONITOR;
        }
 
        /* Verify that MPDUs within one MSDU have sequential PN values.
@@ -799,7 +833,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                int i;
                u8 pn[CCMP_PN_LEN], *rpn;
                if (!rx->key || rx->key->conf.alg != ALG_CCMP)
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, CCMP_PN_LEN);
                for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
                        pn[i]++;
@@ -810,14 +844,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: defrag: CCMP PN not "
-                                      "sequential A2=" MAC_FMT
+                                      "sequential A2=%s"
                                       " PN=%02x%02x%02x%02x%02x%02x "
                                       "(expected %02x%02x%02x%02x%02x%02x)\n",
-                                      rx->dev->name, MAC_ARG(hdr->addr2),
+                                      rx->dev->name, print_mac(mac, 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;
+                       return RX_DROP_UNUSABLE;
                }
                memcpy(entry->last_pn, pn, CCMP_PN_LEN);
        }
@@ -828,7 +862,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
        entry->extra_len += rx->skb->len;
        if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
                rx->skb = NULL;
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
        rx->skb = __skb_dequeue(&entry->skb_list);
@@ -838,7 +872,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                                              GFP_ATOMIC))) {
                        I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
                        __skb_queue_purge(&entry->skb_list);
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
                }
        }
        while ((skb = __skb_dequeue(&entry->skb_list))) {
@@ -856,20 +890,26 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                rx->local->dot11MulticastReceivedFrameCount++;
        else
                ieee80211_led_rx(rx->local);
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
        struct sk_buff *skb;
        int no_pending_pkts;
+       DECLARE_MAC_BUF(mac);
 
        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;
+               return RX_CONTINUE;
+
+       if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
+           (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+               return RX_DROP_UNUSABLE;
 
        skb = skb_dequeue(&rx->sta->tx_filtered);
        if (!skb) {
@@ -889,9 +929,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
                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,
+               printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
+                      print_mac(mac, rx->sta->addr), rx->sta->aid,
                       skb_queue_len(&rx->sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -914,21 +953,21 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
                }
 #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 "
+               printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
                       "though there is no buffered frames for it\n",
-                      rx->dev->name, MAC_ARG(rx->sta->addr));
+                      rx->dev->name, print_mac(mac, rx->sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        }
 
-       /* Free PS Poll skb here instead of returning TXRX_DROP that would
+       /* Free PS Poll skb here instead of returning RX_DROP that would
         * count as an dropped frame. */
        dev_kfree_skb(rx->skb);
 
-       return TXRX_QUEUED;
+       return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 {
        u16 fc = rx->fc;
@@ -936,7 +975,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
 
        if (!WLAN_FC_IS_QOS_DATA(fc))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        /* remove the qos control field, update frame type and meta-data */
        memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
@@ -945,78 +984,67 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
        rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
        hdr->frame_control = cpu_to_le16(fc);
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_802_1x_port_control(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))) {
+       if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
 #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));
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: dropped frame "
+                              "(unauthorized port)\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
-               return TXRX_DROP;
+               return -EACCES;
        }
 
-       return TXRX_CONTINUE;
+       return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_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;
+               return 0;
 
        /* 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)))) {
+                    (rx->key || rx->sdata->drop_unencrypted))) {
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
                               "encryption\n", rx->dev->name);
-               return TXRX_DROP;
+               return -EACCES;
        }
-       return TXRX_CONTINUE;
+       return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_data_to_8023(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 sk_buff *skb = rx->skb;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       DECLARE_MAC_BUF(mac);
+       DECLARE_MAC_BUF(mac2);
+       DECLARE_MAC_BUF(mac3);
+       DECLARE_MAC_BUF(mac4);
 
        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;
+               return -1;
 
        hdrlen = ieee80211_get_hdrlen(fc);
 
@@ -1036,18 +1064,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                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 (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP &&
+                            sdata->vif.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",
+                                      "(BSSID=%s SA=%s DA=%s)\n",
                                       dev->name,
-                                      MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3));
-                       return TXRX_DROP;
+                                      print_mac(mac, hdr->addr1),
+                                      print_mac(mac2, hdr->addr2),
+                                      print_mac(mac3, hdr->addr3));
+                       return -1;
                }
                break;
        case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
@@ -1055,18 +1081,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr3, ETH_ALEN);
                memcpy(src, hdr->addr4, ETH_ALEN);
 
-               if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+               if (unlikely(sdata->vif.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",
+                                      "frame (RA=%s TA=%s DA=%s SA=%s)\n",
                                       rx->dev->name,
-                                      MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3),
-                                      MAC_ARG(hdr->addr4));
-                       return TXRX_DROP;
+                                      print_mac(mac, hdr->addr1),
+                                      print_mac(mac2, hdr->addr2),
+                                      print_mac(mac3, hdr->addr3),
+                                      print_mac(mac4, hdr->addr4));
+                       return -1;
                }
                break;
        case IEEE80211_FCTL_FROMDS:
@@ -1074,40 +1098,39 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr1, ETH_ALEN);
                memcpy(src, hdr->addr3, ETH_ALEN);
 
-               if (sdata->type != IEEE80211_IF_TYPE_STA ||
+               if (sdata->vif.type != IEEE80211_IF_TYPE_STA ||
                    (is_multicast_ether_addr(dst) &&
                     !compare_ether_addr(src, dev->dev_addr)))
-                       return TXRX_DROP;
+                       return -1;
                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 (sdata->vif.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));
+                               printk(KERN_DEBUG "%s: dropped IBSS frame "
+                                      "(DA=%s SA=%s BSSID=%s)\n",
+                                      dev->name,
+                                      print_mac(mac, hdr->addr1),
+                                      print_mac(mac2, hdr->addr2),
+                                      print_mac(mac3, hdr->addr3));
                        }
-                       return TXRX_DROP;
+                       return -1;
                }
                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;
+               return -1;
        }
 
+       payload = skb->data + hdrlen;
        ethertype = (payload[6] << 8) | payload[7];
 
        if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
@@ -1121,6 +1144,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
        } else {
                struct ethhdr *ehdr;
                __be16 len;
+
                skb_pull(skb, hdrlen);
                len = htons(skb->len);
                ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
@@ -1128,36 +1152,72 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(ehdr->h_source, src, ETH_ALEN);
                ehdr->h_proto = len;
        }
-       skb->dev = dev;
+       return 0;
+}
 
-       skb2 = NULL;
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+{
+       static const u8 pae_group_addr[ETH_ALEN]
+               = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
+       struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
 
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
+       /*
+        * Allow EAPOL frames to us/the PAE group address regardless
+        * of whether the frame was encrypted or not.
+        */
+       if (ehdr->h_proto == htons(ETH_P_PAE) &&
+           (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+            compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
+               return true;
+
+       if (ieee80211_802_1x_port_control(rx) ||
+           ieee80211_drop_unencrypted(rx))
+               return false;
+
+       return true;
+}
+
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+static void
+ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+{
+       struct net_device *dev = rx->dev;
+       struct ieee80211_local *local = rx->local;
+       struct sk_buff *skb, *xmit_skb;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
+       struct sta_info *dsta;
 
-       if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-           || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+       skb = rx->skb;
+       xmit_skb = NULL;
+
+       if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+                                     sdata->vif.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())
+               if (is_multicast_ether_addr(ehdr->h_dest)) {
+                       /*
+                        * send multicast frames both to higher layers in
+                        * local net stack and back to the wireless medium
+                        */
+                       xmit_skb = skb_copy(skb, GFP_ATOMIC);
+                       if (!xmit_skb && 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.
+                       if (dsta && dsta->dev == dev) {
+                               /*
+                                * The destination station is associated to
+                                * this AP (in this VLAN), so send the frame
+                                * directly to it and do not pass it to local
+                                * net stack.
                                 */
-                               skb2 = skb;
+                               xmit_skb = skb;
                                skb = NULL;
                        }
                        if (dsta)
@@ -1172,84 +1232,232 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                netif_rx(skb);
        }
 
-       if (skb2) {
+       if (xmit_skb) {
                /* 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);
+               xmit_skb->protocol = __constant_htons(ETH_P_802_3);
+               skb_reset_network_header(xmit_skb);
+               skb_reset_mac_header(xmit_skb);
+               dev_queue_xmit(xmit_skb);
        }
-
-       return TXRX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct net_device *dev = rx->dev;
+       struct ieee80211_local *local = rx->local;
+       u16 fc, ethertype;
+       u8 *payload;
+       struct sk_buff *skb = rx->skb, *frame = NULL;
+       const struct ethhdr *eth;
+       int remaining, err;
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       DECLARE_MAC_BUF(mac);
 
-       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_DROP;
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return RX_CONTINUE;
 
-       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;
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return RX_DROP_MONITOR;
 
-       return TXRX_QUEUED;
+       if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
+               return RX_CONTINUE;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return RX_DROP_UNUSABLE;
+
+       skb->dev = dev;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+
+       /* skip the wrapping header */
+       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+       if (!eth)
+               return RX_DROP_UNUSABLE;
+
+       while (skb != frame) {
+               u8 padding;
+               __be16 len = eth->h_proto;
+               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+               remaining = skb->len;
+               memcpy(dst, eth->h_dest, ETH_ALEN);
+               memcpy(src, eth->h_source, ETH_ALEN);
+
+               padding = ((4 - subframe_len) & 0x3);
+               /* the last MSDU has no padding */
+               if (subframe_len > remaining) {
+                       printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
+                       return RX_DROP_UNUSABLE;
+               }
+
+               skb_pull(skb, sizeof(struct ethhdr));
+               /* if last subframe reuse skb */
+               if (remaining <= subframe_len + padding)
+                       frame = skb;
+               else {
+                       frame = dev_alloc_skb(local->hw.extra_tx_headroom +
+                                             subframe_len);
+
+                       if (frame == NULL)
+                               return RX_DROP_UNUSABLE;
+
+                       skb_reserve(frame, local->hw.extra_tx_headroom +
+                                   sizeof(struct ethhdr));
+                       memcpy(skb_put(frame, ntohs(len)), skb->data,
+                               ntohs(len));
+
+                       eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
+                                                       padding);
+                       if (!eth) {
+                               printk(KERN_DEBUG "%s: wrong buffer size ",
+                                      dev->name);
+                               dev_kfree_skb(frame);
+                               return RX_DROP_UNUSABLE;
+                       }
+               }
+
+               skb_reset_network_header(frame);
+               frame->dev = dev;
+               frame->priority = skb->priority;
+               rx->skb = frame;
+
+               payload = frame->data;
+               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(frame, 6);
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               } else {
+                       memcpy(skb_push(frame, sizeof(__be16)),
+                              &len, sizeof(__be16));
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               }
+
+               if (!ieee80211_frame_allowed(rx)) {
+                       if (skb == frame) /* last frame */
+                               return RX_DROP_UNUSABLE;
+                       dev_kfree_skb(frame);
+                       continue;
+               }
+
+               ieee80211_deliver_skb(rx);
+       }
+
+       return RX_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)
+static ieee80211_rx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 {
-       ieee80211_rx_handler *handler;
-       ieee80211_txrx_result res = TXRX_DROP;
+       struct net_device *dev = rx->dev;
+       u16 fc;
+       int err;
 
-       for (handler = handlers; *handler != NULL; handler++) {
-               res = (*handler)(rx);
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return RX_CONTINUE;
 
-               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;
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return RX_DROP_MONITOR;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return RX_DROP_UNUSABLE;
+
+       if (!ieee80211_frame_allowed(rx))
+               return RX_DROP_MONITOR;
+
+       rx->skb->dev = dev;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += rx->skb->len;
+
+       ieee80211_deliver_skb(rx);
+
+       return RX_QUEUED;
+}
+
+static ieee80211_rx_result
+ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_hw *hw = &local->hw;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 start_seq_num;
+       u16 tid;
+
+       if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
+               return RX_CONTINUE;
+
+       if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
+               if (!rx->sta)
+                       return RX_CONTINUE;
+               tid = le16_to_cpu(bar->control) >> 12;
+               tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
+               if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+                       return RX_CONTINUE;
+
+               start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
+
+               /* reset session timer */
+               if (tid_agg_rx->timeout) {
+                       unsigned long expires =
+                               jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+                       mod_timer(&tid_agg_rx->session_timer, expires);
                }
-               break;
+
+               /* manage reordering buffer according to requested */
+               /* sequence number */
+               rcu_read_lock();
+               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+                                                start_seq_num, 1);
+               rcu_read_unlock();
+               return RX_DROP_UNUSABLE;
        }
 
-       if (res == TXRX_DROP)
-               dev_kfree_skb(rx->skb);
-       return res;
+       return RX_CONTINUE;
 }
 
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-                                               ieee80211_rx_handler *handlers,
-                                               struct ieee80211_txrx_data *rx,
-                                               struct sta_info *sta)
+static ieee80211_rx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
 {
-       if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
-           TXRX_CONTINUE)
-               dev_kfree_skb(rx->skb);
+       struct ieee80211_sub_if_data *sdata;
+
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return RX_DROP_MONITOR;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+            sdata->vif.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 RX_DROP_MONITOR;
+
+       return RX_QUEUED;
 }
 
 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;
+       DECLARE_MAC_BUF(mac);
+       DECLARE_MAC_BUF(mac2);
 
        hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
        if (rx->skb->len >= hdrlen + 4)
@@ -1259,19 +1467,19 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 
        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);
+                      "failure from %s to %s keyidx=%d\n",
+                      dev->name, print_mac(mac, hdr->addr2),
+                      print_mac(mac2, hdr->addr1), keyidx);
 
-       if (!sta) {
+       if (!rx->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));
+                              "error for unknown address %s\n",
+                              dev->name, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1279,11 +1487,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                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));
+                              "%s)\n", dev->name, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
-       if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
+       if (rx->sdata->vif.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
@@ -1293,8 +1501,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                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));
+                              " (src %s)\n", dev->name, keyidx,
+                              print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1304,8 +1512,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                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));
+                              "(fc=0x%04x) (src %s)\n",
+                              dev->name, rx->fc, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1315,7 +1523,88 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
        rx->skb = NULL;
 }
 
-ieee80211_rx_handler ieee80211_rx_handlers[] =
+static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_rtap_hdr {
+               struct ieee80211_radiotap_header hdr;
+               u8 flags;
+               u8 rate;
+               __le16 chan_freq;
+               __le16 chan_flags;
+       } __attribute__ ((packed)) *rthdr;
+       struct sk_buff *skb = rx->skb, *skb2;
+       struct net_device *prev_dev = NULL;
+       struct ieee80211_rx_status *status = rx->u.rx.status;
+
+       if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED)
+               goto out_free_skb;
+
+       if (skb_headroom(skb) < sizeof(*rthdr) &&
+           pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
+               goto out_free_skb;
+
+       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));
+
+       rthdr->rate = rx->u.rx.rate->bitrate / 5;
+       rthdr->chan_freq = cpu_to_le16(status->freq);
+
+       if (status->band == IEEE80211_BAND_5GHZ)
+               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);
+
+       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->vif.type != IEEE80211_IF_TYPE_MNTR ||
+                   !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                       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);
+               skb = NULL;
+       } else
+               goto out_free_skb;
+
+       rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED;
+       return;
+
+ out_free_skb:
+       dev_kfree_skb(skb);
+}
+
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *);
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
 {
        ieee80211_rx_h_if_stats,
        ieee80211_rx_h_passive_scan,
@@ -1330,13 +1619,54 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
         * 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_amsdu,
        ieee80211_rx_h_data,
+       ieee80211_rx_h_ctrl,
        ieee80211_rx_h_mgmt,
        NULL
 };
 
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_txrx_data *rx,
+                                        struct sk_buff *skb)
+{
+       ieee80211_rx_handler *handler;
+       ieee80211_rx_result res = RX_DROP_MONITOR;
+
+       rx->skb = skb;
+       rx->sdata = sdata;
+       rx->dev = sdata->dev;
+
+       for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) {
+               res = (*handler)(rx);
+
+               switch (res) {
+               case RX_CONTINUE:
+                       continue;
+               case RX_DROP_UNUSABLE:
+               case RX_DROP_MONITOR:
+                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
+                       if (rx->sta)
+                               rx->sta->rx_dropped++;
+                       break;
+               case RX_QUEUED:
+                       I802_DEBUG_INC(sdata->local->rx_handlers_queued);
+                       break;
+               }
+               break;
+       }
+
+       switch (res) {
+       case RX_CONTINUE:
+       case RX_DROP_MONITOR:
+               ieee80211_rx_cooked_monitor(rx);
+               break;
+       case RX_DROP_UNUSABLE:
+               dev_kfree_skb(rx->skb);
+               break;
+       }
+}
+
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
@@ -1345,7 +1675,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 {
        int multicast = is_multicast_ether_addr(hdr->addr1);
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_STA:
                if (!bssid)
                        return 0;
@@ -1416,99 +1746,70 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 }
 
 /*
- * This is the receive path handler. It is called by a low level driver when an
- * 802.11 MPDU is received from the hardware.
+ * This is the actual Rx frames handler. as it blongs to Rx path it must
+ * be called with rcu_read_lock protection.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status)
+static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+                                        struct sk_buff *skb,
+                                        struct ieee80211_rx_status *status,
+                                        u32 load,
+                                        struct ieee80211_rate *rate)
 {
        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;
+       int prepares;
        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.u.rx.load = load;
+       rx.u.rx.rate = rate;
        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.sta = sta_info_get(local, hdr->addr2);
+       if (rx.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);
+               ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
                goto end;
        }
 
-       if (unlikely(local->sta_scanning))
+       if (unlikely(local->sta_sw_scanning || local->sta_hw_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;
-       }
+       ieee80211_parse_qos(&rx);
+       ieee80211_verify_ip_alignment(&rx);
 
-       bssid = ieee80211_get_bssid(hdr, skb->len);
+       skb = rx.skb;
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+               if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR)
                        continue;
 
+               bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
                rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-               prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
-               /* prepare_for_handlers can change sta */
-               sta = rx.sta;
+               prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
 
-               if (!prepres)
+               if (!prepares)
                        continue;
 
                /*
@@ -1536,27 +1837,266 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                                       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);
+               rx.fc = le16_to_cpu(hdr->frame_control);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
                prev = sdata;
        }
        if (prev) {
-               rx.skb = skb;
-               rx.dev = prev->dev;
-               rx.sdata = prev;
-               ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-                                            &rx, sta);
+               rx.fc = le16_to_cpu(hdr->frame_control);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb);
        } else
                dev_kfree_skb(skb);
 
  end:
-       rcu_read_unlock();
+       if (rx.sta)
+               sta_info_put(rx.sta);
+}
 
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK   0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+       return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+       return ((sq + 1) & SEQ_MASK);
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+       return ((sq1 - sq2) & SEQ_MASK);
+}
+
+
+/*
+ * As it function blongs to Rx path it must be called with
+ * the proper rcu_read_lock protection for its flow.
+ */
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+                               struct tid_ampdu_rx *tid_agg_rx,
+                               struct sk_buff *skb, u16 mpdu_seq_num,
+                               int bar_req)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_rx_status status;
+       u16 head_seq_num, buf_size;
+       int index;
+       u32 pkt_load;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_rate *rate;
+
+       buf_size = tid_agg_rx->buf_size;
+       head_seq_num = tid_agg_rx->head_seq_num;
+
+       /* frame with out of date sequence number */
+       if (seq_less(mpdu_seq_num, head_seq_num)) {
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+       /* if frame sequence number exceeds our buffering window size or
+        * block Ack Request arrived - release stored frames */
+       if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
+               /* new head to the ordering buffer */
+               if (bar_req)
+                       head_seq_num = mpdu_seq_num;
+               else
+                       head_seq_num =
+                               seq_inc(seq_sub(mpdu_seq_num, buf_size));
+               /* release stored frames up to new head to stack */
+               while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+                       index = seq_sub(tid_agg_rx->head_seq_num,
+                               tid_agg_rx->ssn)
+                               % tid_agg_rx->buf_size;
+
+                       if (tid_agg_rx->reorder_buf[index]) {
+                               /* release the reordered frames to stack */
+                               memcpy(&status,
+                                       tid_agg_rx->reorder_buf[index]->cb,
+                                       sizeof(status));
+                               sband = local->hw.wiphy->bands[status.band];
+                               rate = &sband->bitrates[status.rate_idx];
+                               pkt_load = ieee80211_rx_load_stats(local,
+                                               tid_agg_rx->reorder_buf[index],
+                                               &status, rate);
+                               __ieee80211_rx_handle_packet(hw,
+                                       tid_agg_rx->reorder_buf[index],
+                                       &status, pkt_load, rate);
+                               tid_agg_rx->stored_mpdu_num--;
+                               tid_agg_rx->reorder_buf[index] = NULL;
+                       }
+                       tid_agg_rx->head_seq_num =
+                               seq_inc(tid_agg_rx->head_seq_num);
+               }
+               if (bar_req)
+                       return 1;
+       }
+
+       /* now the new frame is always in the range of the reordering */
+       /* buffer window */
+       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
+                               % tid_agg_rx->buf_size;
+       /* check if we already stored this frame */
+       if (tid_agg_rx->reorder_buf[index]) {
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+       /* if arrived mpdu is in the right order and nothing else stored */
+       /* release it immediately */
+       if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
+                       tid_agg_rx->stored_mpdu_num == 0) {
+               tid_agg_rx->head_seq_num =
+                       seq_inc(tid_agg_rx->head_seq_num);
+               return 0;
+       }
+
+       /* put the frame in the reordering buffer */
+       tid_agg_rx->reorder_buf[index] = skb;
+       tid_agg_rx->stored_mpdu_num++;
+       /* release the buffer until next missing frame */
+       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
+                                               % tid_agg_rx->buf_size;
+       while (tid_agg_rx->reorder_buf[index]) {
+               /* release the reordered frame back to stack */
+               memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
+                       sizeof(status));
+               sband = local->hw.wiphy->bands[status.band];
+               rate = &sband->bitrates[status.rate_idx];
+               pkt_load = ieee80211_rx_load_stats(local,
+                                       tid_agg_rx->reorder_buf[index],
+                                       &status, rate);
+               __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
+                                            &status, pkt_load, rate);
+               tid_agg_rx->stored_mpdu_num--;
+               tid_agg_rx->reorder_buf[index] = NULL;
+               tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+               index = seq_sub(tid_agg_rx->head_seq_num,
+                       tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+       }
+       return 1;
+}
+
+static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+                                    struct sk_buff *skb)
+{
+       struct ieee80211_hw *hw = &local->hw;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct sta_info *sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 fc, sc;
+       u16 mpdu_seq_num;
+       u8 ret = 0, *qc;
+       int tid;
+
+       sta = sta_info_get(local, hdr->addr2);
+       if (!sta)
+               return ret;
+
+       fc = le16_to_cpu(hdr->frame_control);
+
+       /* filter the QoS data rx stream according to
+        * STA/TID and check if this STA/TID is on aggregation */
+       if (!WLAN_FC_IS_QOS_DATA(fc))
+               goto end_reorder;
+
+       qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN;
+       tid = qc[0] & QOS_CONTROL_TID_MASK;
+       tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]);
+
+       if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+               goto end_reorder;
+
+       /* null data frames are excluded */
+       if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
+               goto end_reorder;
+
+       /* new un-ordered ampdu frame - process it */
+
+       /* reset session timer */
+       if (tid_agg_rx->timeout) {
+               unsigned long expires =
+                       jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+               mod_timer(&tid_agg_rx->session_timer, expires);
+       }
+
+       /* if this mpdu is fragmented - terminate rx aggregation session */
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       if (sc & IEEE80211_SCTL_FRAG) {
+               ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+               ret = 1;
+               goto end_reorder;
+       }
+
+       /* according to mpdu sequence number deal with reordering buffer */
+       mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
+       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+                                               mpdu_seq_num, 0);
+end_reorder:
        if (sta)
                sta_info_put(sta);
+       return ret;
+}
+
+/*
+ * 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);
+       u32 pkt_load;
+       struct ieee80211_rate *rate = NULL;
+       struct ieee80211_supported_band *sband;
+
+       if (status->band < 0 ||
+           status->band > IEEE80211_NUM_BANDS) {
+               WARN_ON(1);
+               return;
+       }
+
+       sband = local->hw.wiphy->bands[status->band];
+
+       if (!sband ||
+           status->rate_idx < 0 ||
+           status->rate_idx >= sband->n_bitrates) {
+               WARN_ON(1);
+               return;
+       }
+
+       rate = &sband->bitrates[status->rate_idx];
+
+       /*
+        * 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, rate);
+       if (!skb) {
+               rcu_read_unlock();
+               return;
+       }
+
+       pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
+       local->channel_use_raw += pkt_load;
+
+       if (!ieee80211_rx_reorder_ampdu(local, skb))
+               __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(__ieee80211_rx);
 
index 4ed1b60bb1caa23812987231b4218adaf3fe3a11..6b53783966b2c2c43849997b23f5e5d05ea28087 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/timer.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -73,36 +74,13 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
 }
 EXPORT_SYMBOL(sta_info_get);
 
-int sta_info_min_txrate_get(struct ieee80211_local *local)
-{
-       struct sta_info *sta;
-       struct ieee80211_hw_mode *mode;
-       int min_txrate = 9999999;
-       int i;
-
-       read_lock_bh(&local->sta_lock);
-       mode = local->oper_hw_mode;
-       for (i = 0; i < STA_HASH_SIZE; i++) {
-               sta = local->sta_hash[i];
-               while (sta) {
-                       if (sta->txrate < min_txrate)
-                               min_txrate = sta->txrate;
-                       sta = sta->hnext;
-               }
-       }
-       read_unlock_bh(&local->sta_lock);
-       if (min_txrate == 9999999)
-               min_txrate = 0;
-
-       return mode->rates[min_txrate].rate;
-}
-
 
 static void sta_info_release(struct kref *kref)
 {
        struct sta_info *sta = container_of(kref, struct sta_info, kref);
        struct ieee80211_local *local = sta->local;
        struct sk_buff *skb;
+       int i;
 
        /* free sta structure; it has already been removed from
         * hash table etc. external structures. Make sure that all
@@ -115,6 +93,10 @@ static void sta_info_release(struct kref *kref)
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
                dev_kfree_skb_any(skb);
        }
+       for (i = 0; i <  STA_TID_NUM; i++) {
+               del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
+               del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
+       }
        rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
        rate_control_put(sta->rate_ctrl);
        kfree(sta);
@@ -132,6 +114,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
                               struct net_device *dev, u8 *addr, gfp_t gfp)
 {
        struct sta_info *sta;
+       int i;
+       DECLARE_MAC_BUF(mac);
 
        sta = kzalloc(sizeof(*sta), gfp);
        if (!sta)
@@ -150,6 +134,28 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
        memcpy(sta->addr, addr, ETH_ALEN);
        sta->local = local;
        sta->dev = dev;
+       spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
+       spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
+       for (i = 0; i < STA_TID_NUM; i++) {
+               /* timer_to_tid must be initialized with identity mapping to
+                * enable session_timer's data differentiation. refer to
+                * sta_rx_agg_session_timer_expired for useage */
+               sta->timer_to_tid[i] = i;
+               /* tid to tx queue: initialize according to HW (0 is valid) */
+               sta->tid_to_tx_q[i] = local->hw.queues;
+               /* rx timers */
+               sta->ampdu_mlme.tid_rx[i].session_timer.function =
+                       sta_rx_agg_session_timer_expired;
+               sta->ampdu_mlme.tid_rx[i].session_timer.data =
+                       (unsigned long)&sta->timer_to_tid[i];
+               init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
+               /* tx timers */
+               sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
+                       sta_addba_resp_timer_expired;
+               sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
+                       (unsigned long)&sta->timer_to_tid[i];
+               init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
+       }
        skb_queue_head_init(&sta->ps_tx_buf);
        skb_queue_head_init(&sta->tx_filtered);
        __sta_info_get(sta);    /* sta used by caller, decremented by
@@ -158,14 +164,21 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
        list_add(&sta->list, &local->sta_list);
        local->num_sta++;
        sta_info_hash_add(local, sta);
-       if (local->ops->sta_notify)
-               local->ops->sta_notify(local_to_hw(local), dev->ifindex,
-                                       STA_NOTIFY_ADD, addr);
+       if (local->ops->sta_notify) {
+               struct ieee80211_sub_if_data *sdata;
+
+               sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+               if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+                       sdata = sdata->u.vlan.ap;
+
+               local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+                                      STA_NOTIFY_ADD, addr);
+       }
        write_unlock_bh(&local->sta_lock);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
-              wiphy_name(local->hw.wiphy), MAC_ARG(addr));
+       printk(KERN_DEBUG "%s: Added STA %s\n",
+              wiphy_name(local->hw.wiphy), print_mac(mac, addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -204,6 +217,7 @@ void sta_info_free(struct sta_info *sta)
 {
        struct sk_buff *skb;
        struct ieee80211_local *local = sta->local;
+       DECLARE_MAC_BUF(mac);
 
        might_sleep();
 
@@ -220,16 +234,24 @@ void sta_info_free(struct sta_info *sta)
        }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
-              wiphy_name(local->hw.wiphy), MAC_ARG(sta->addr));
+       printk(KERN_DEBUG "%s: Removed STA %s\n",
+              wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
        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);
+       if (local->ops->sta_notify) {
+               struct ieee80211_sub_if_data *sdata;
+
+               sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+               if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+                       sdata = sdata->u.vlan.ap;
+
+               local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+                                      STA_NOTIFY_REMOVE, sta->addr);
+       }
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
@@ -264,6 +286,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 {
        unsigned long flags;
        struct sk_buff *skb;
+       DECLARE_MAC_BUF(mac);
 
        if (skb_queue_empty(&sta->ps_tx_buf))
                return;
@@ -282,7 +305,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                if (skb) {
                        local->total_ps_buffered--;
                        printk(KERN_DEBUG "Buffered frame expired (STA "
-                              MAC_FMT ")\n", MAC_ARG(sta->addr));
+                              "%s)\n", print_mac(mac, sta->addr));
                        dev_kfree_skb(skb);
                } else
                        break;
@@ -303,7 +326,8 @@ static void sta_info_cleanup(unsigned long data)
        }
        read_unlock_bh(&local->sta_lock);
 
-       local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+       local->sta_cleanup.expires =
+               round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
        add_timer(&local->sta_cleanup);
 }
 
@@ -342,7 +366,8 @@ void sta_info_init(struct ieee80211_local *local)
        INIT_LIST_HEAD(&local->sta_list);
 
        init_timer(&local->sta_cleanup);
-       local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+       local->sta_cleanup.expires =
+               round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
        local->sta_cleanup.data = (unsigned long) local;
        local->sta_cleanup.function = sta_info_cleanup;
 
index 8f7ebe41c0246a91d687a1ac91e79509dc062b5f..19f3fb41294052303afb2706335ac7ac4143aebe 100644 (file)
 #include <linux/kref.h>
 #include "ieee80211_key.h"
 
-/* Stations flags (struct sta_info::flags) */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
-                                   * controlling whether STA is authorized to
-                                   * 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_WDS BIT(27)
+/**
+ * enum ieee80211_sta_info_flags - Stations flags
+ *
+ * These flags are used with &struct sta_info's @flags member.
+ *
+ * @WLAN_STA_AUTH: Station is authenticated.
+ * @WLAN_STA_ASSOC: Station is associated.
+ * @WLAN_STA_PS: Station is in power-save mode
+ * @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered)
+ * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
+ *     This bit is always checked so needs to be enabled for all stations
+ *     when virtual port control is not in use.
+ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
+ *     frames.
+ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
+ * @WLAN_STA_WME: Station is a QoS-STA.
+ * @WLAN_STA_WDS: Station is one of our WDS peers.
+ */
+enum ieee80211_sta_info_flags {
+       WLAN_STA_AUTH           = 1<<0,
+       WLAN_STA_ASSOC          = 1<<1,
+       WLAN_STA_PS             = 1<<2,
+       WLAN_STA_TIM            = 1<<3,
+       WLAN_STA_AUTHORIZED     = 1<<4,
+       WLAN_STA_SHORT_PREAMBLE = 1<<5,
+       WLAN_STA_ASSOC_AP       = 1<<6,
+       WLAN_STA_WME            = 1<<7,
+       WLAN_STA_WDS            = 1<<8,
+};
+
+#define STA_TID_NUM 16
+#define ADDBA_RESP_INTERVAL HZ
+#define HT_AGG_MAX_RETRIES             (0x3)
 
+#define HT_AGG_STATE_INITIATOR_SHIFT   (4)
+
+#define HT_ADDBA_REQUESTED_MSK         BIT(0)
+#define HT_ADDBA_DRV_READY_MSK         BIT(1)
+#define HT_ADDBA_RECEIVED_MSK          BIT(2)
+#define HT_AGG_STATE_REQ_STOP_BA_MSK   BIT(3)
+#define HT_AGG_STATE_INITIATOR_MSK      BIT(HT_AGG_STATE_INITIATOR_SHIFT)
+#define HT_AGG_STATE_IDLE              (0x0)
+#define HT_AGG_STATE_OPERATIONAL       (HT_ADDBA_REQUESTED_MSK |       \
+                                        HT_ADDBA_DRV_READY_MSK |       \
+                                        HT_ADDBA_RECEIVED_MSK)
+
+/**
+ * struct tid_ampdu_tx - TID aggregation information (Tx).
+ *
+ * @state: TID's state in session state machine.
+ * @dialog_token: dialog token for aggregation session
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @addba_resp_timer: timer for peer's response to addba request
+ * @addba_req_num: number of times addBA request has been sent.
+ */
+struct tid_ampdu_tx {
+       u8 state;
+       u8 dialog_token;
+       u16 ssn;
+       struct timer_list addba_resp_timer;
+       u8 addba_req_num;
+};
+
+/**
+ * struct tid_ampdu_rx - TID aggregation information (Rx).
+ *
+ * @state: TID's state in session state machine.
+ * @dialog_token: dialog token for aggregation session
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @buf_size: buffer size for incoming A-MPDUs
+ * @timeout: reset timer value.
+ * @head_seq_num: head sequence number in reordering buffer.
+ * @stored_mpdu_num: number of MPDUs in reordering buffer
+ * @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ */
+struct tid_ampdu_rx {
+       u8 state;
+       u8 dialog_token;
+       u16 ssn;
+       u16 buf_size;
+       u16 timeout;
+       u16 head_seq_num;
+       u16 stored_mpdu_num;
+       struct sk_buff **reorder_buf;
+       struct timer_list session_timer;
+};
+
+/**
+ * struct sta_ampdu_mlme - STA aggregation information.
+ *
+ * @tid_rx: aggregation info for Rx per TID
+ * @tid_tx: aggregation info for Tx per TID
+ * @ampdu_rx: for locking sections in aggregation Rx flow
+ * @ampdu_tx: for locking sectionsi in aggregation Tx flow
+ * @dialog_token_allocator: dialog token enumerator for each new session;
+ */
+struct sta_ampdu_mlme {
+       struct tid_ampdu_rx tid_rx[STA_TID_NUM];
+       struct tid_ampdu_tx tid_tx[STA_TID_NUM];
+       spinlock_t ampdu_rx;
+       spinlock_t ampdu_tx;
+       u8 dialog_token_allocator;
+};
 
 struct sta_info {
        struct kref kref;
@@ -59,10 +147,11 @@ struct sta_info {
        unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
 
        unsigned long last_rx;
-       u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
-       int txrate; /* index in local->curr_rates */
-       int last_txrate; /* last rate used to send a frame to this STA */
-       int last_nonerp_idx;
+       /* bitmap of supported rates per band */
+       u64 supp_rates[IEEE80211_NUM_BANDS];
+       int txrate_idx;
+       /* last rates used to send a frame to this STA */
+       int last_txrate_idx, last_nonerp_txrate_idx;
 
        struct net_device *dev; /* which net device is this station associated
                                 * to */
@@ -99,6 +188,12 @@ struct sta_info {
 
        u16 listen_interval;
 
+       struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities
+                                            of this STA */
+       struct sta_ampdu_mlme ampdu_mlme;
+       u8 timer_to_tid[STA_TID_NUM];   /* convert timer id to tid */
+       u8 tid_to_tx_q[STA_TID_NUM];    /* map tid to tx queue */
+
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct sta_info_debugfsdentries {
                struct dentry *dir;
@@ -112,6 +207,7 @@ struct sta_info {
                struct dentry *wme_rx_queue;
                struct dentry *wme_tx_queue;
 #endif
+               struct dentry *agg_status;
        } debugfs;
 #endif
 };
@@ -141,7 +237,6 @@ static inline void __sta_info_get(struct sta_info *sta)
 }
 
 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);
index 876cbe37107a3138dacc4072609841daba764948..3abe194e4d55328ae61aba0bdcd1515a299212fd 100644 (file)
@@ -276,9 +276,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
             (iv32 == key->u.tkip.iv32_rx[queue] &&
              iv16 <= key->u.tkip.iv16_rx[queue]))) {
 #ifdef CONFIG_TKIP_DEBUG
+               DECLARE_MAC_BUF(mac);
                printk(KERN_DEBUG "TKIP replay detected for RX frame from "
-                      MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
-                      MAC_ARG(ta),
+                      "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+                      print_mac(mac, ta),
                       iv32, iv16, key->u.tkip.iv32_rx[queue],
                       key->u.tkip.iv16_rx[queue]);
 #endif /* CONFIG_TKIP_DEBUG */
@@ -300,8 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 #ifdef CONFIG_TKIP_DEBUG
                {
                        int i;
-                       printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT
-                              " TK=", MAC_ARG(ta));
+                       DECLARE_MAC_BUF(mac);
+                       printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
+                              " TK=", print_mac(mac, ta));
                        for (i = 0; i < 16; i++)
                                printk("%02x ",
                                       key->conf.key[
index 957ec3c830679fbf1b3cae2f6c9911a8cc182b4f..181d97015f614cb733f32bba8949af2a1be645c1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -53,6 +54,7 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
        const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 fc;
        int hdrlen;
+       DECLARE_MAC_BUF(mac);
 
        printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
        if (skb->len < 4) {
@@ -68,13 +70,13 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
                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));
+               printk(" A1=%s", print_mac(mac, hdr->addr1));
        if (hdrlen >= 16)
-               printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
+               printk(" A2=%s", print_mac(mac, hdr->addr2));
        if (hdrlen >= 24)
-               printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
+               printk(" A3=%s", print_mac(mac, hdr->addr3));
        if (hdrlen >= 30)
-               printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
+               printk(" A4=%s", print_mac(mac, hdr->addr4));
        printk("\n");
 }
 #else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
@@ -90,9 +92,13 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
        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;
+       struct ieee80211_supported_band *sband;
 
-       erp = txrate->flags & IEEE80211_RATE_ERP;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       erp = 0;
+       if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
        /*
         * data and mgmt (except PS Poll):
@@ -148,20 +154,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
         * 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;
+       /* use lowest available if everything fails */
+       mrate = sband->bitrates[0].bitrate;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               struct ieee80211_rate *r = &sband->bitrates[i];
 
-               if (IEEE80211_RATE_MODULATION(txrate->flags) !=
-                   IEEE80211_RATE_MODULATION(r->flags))
-                       continue;
+               if (r->bitrate > txrate->bitrate)
+                       break;
 
-               if (r->flags & IEEE80211_RATE_BASIC)
-                       rate = r->rate;
-               else if (r->flags & IEEE80211_RATE_MANDATORY)
-                       mrate = r->rate;
+               if (tx->sdata->basic_rates & BIT(i))
+                       rate = r->bitrate;
+
+               switch (sband->band) {
+               case IEEE80211_BAND_2GHZ: {
+                       u32 flag;
+                       if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+                               flag = IEEE80211_RATE_MANDATORY_G;
+                       else
+                               flag = IEEE80211_RATE_MANDATORY_B;
+                       if (r->flags & flag)
+                               mrate = r->bitrate;
+                       break;
+               }
+               case IEEE80211_BAND_5GHZ:
+                       if (r->flags & IEEE80211_RATE_MANDATORY_A)
+                               mrate = r->bitrate;
+                       break;
+               case IEEE80211_NUM_BANDS:
+                       WARN_ON(1);
+                       break;
+               }
        }
        if (rate == -1) {
                /* No matching basic rate found; use highest suitable mandatory
@@ -174,7 +196,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
         * to closest integer */
 
        dur = ieee80211_frame_duration(local, 10, rate, erp,
-                      tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
+                               tx->sdata->bss_conf.use_short_preamble);
 
        if (next_frag_len) {
                /* Frame is fragmented: duration increases with time needed to
@@ -182,9 +204,8 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
                dur *= 2; /* ACK + SIFS */
                /* next fragment */
                dur += ieee80211_frame_duration(local, next_frag_len,
-                               txrate->rate, erp,
-                               tx->sdata->flags &
-                                       IEEE80211_SDATA_SHORT_PREAMBLE);
+                               txrate->bitrate, erp,
+                               tx->sdata->bss_conf.use_short_preamble);
        }
 
        return dur;
@@ -211,7 +232,7 @@ static int inline is_ieee80211_device(struct net_device *dev,
 
 /* tx handlers */
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -221,58 +242,48 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
        u32 sta_flags;
 
        if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
 
-       if (unlikely(tx->local->sta_scanning != 0) &&
+       if (unlikely(tx->local->sta_sw_scanning) &&
            ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
             (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
-               return TXRX_DROP;
+               return TX_DROP;
 
        if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
-               return TXRX_CONTINUE;
+               return TX_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->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
                             (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       DECLARE_MAC_BUF(mac);
                        printk(KERN_DEBUG "%s: dropped data frame to not "
-                              "associated station " MAC_FMT "\n",
-                              tx->dev->name, MAC_ARG(hdr->addr1));
+                              "associated station %s\n",
+                              tx->dev->name, print_mac(mac, hdr->addr1));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
                        I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
-                       return TXRX_DROP;
+                       return TX_DROP;
                }
        } else {
                if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
                             tx->local->num_sta == 0 &&
-                            tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
+                            tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS)) {
                        /*
                         * No associated STAs - no need to send multicast
                         * frames.
                         */
-                       return TXRX_DROP;
+                       return TX_DROP;
                }
-               return TXRX_CONTINUE;
+               return TX_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;
+       return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@@ -280,7 +291,7 @@ ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
        if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
                ieee80211_include_sequence(tx->sdata, hdr);
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
 /* This function is called whenever the AP is about to exceed the maximum limit
@@ -302,7 +313,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
        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)
+                   sdata->vif.type != IEEE80211_IF_TYPE_AP)
                        continue;
                ap = &sdata->u.ap;
                skb = skb_dequeue(&ap->ps_bc_buf);
@@ -330,16 +341,27 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
               wiphy_name(local->hw.wiphy), purged);
 }
 
-static inline ieee80211_txrx_result
+static ieee80211_tx_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)) {
+       /*
+        * 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.
+        * This is done either by the hardware or us.
+        */
+
+       /* not AP/IBSS or ordered frame */
+       if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
+               return TX_CONTINUE;
+
+       /* no stations in PS mode */
+       if (!atomic_read(&tx->sdata->bss->num_sta_ps))
+               return TX_CONTINUE;
+
+       /* buffered in mac80211 */
+       if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) {
                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) >=
@@ -353,28 +375,32 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
                } else
                        tx->local->total_ps_buffered++;
                skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
-               return TXRX_QUEUED;
+               return TX_QUEUED;
        }
 
-       return TXRX_CONTINUE;
+       /* buffered in hardware */
+       tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+
+       return TX_CONTINUE;
 }
 
-static inline ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 {
        struct sta_info *sta = tx->sta;
+       DECLARE_MAC_BUF(mac);
 
        if (unlikely(!sta ||
                     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
                      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
-               return TXRX_CONTINUE;
+               return TX_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 "
+               printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
                       "before %d)\n",
-                      MAC_ARG(sta->addr), sta->aid,
+                      print_mac(mac, sta->addr), sta->aid,
                       skb_queue_len(&sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                sta->flags |= WLAN_STA_TIM;
@@ -383,9 +409,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
                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 "
+                               printk(KERN_DEBUG "%s: STA %s TX "
                                       "buffer full - dropping oldest frame\n",
-                                      tx->dev->name, MAC_ARG(sta->addr));
+                                      tx->dev->name, print_mac(mac, sta->addr));
                        }
                        dev_kfree_skb(old);
                } else
@@ -401,26 +427,25 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
                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;
+               return TX_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 "
+               printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
                       "set -> send frame\n", tx->dev->name,
-                      MAC_ARG(sta->addr));
+                      print_mac(mac, sta->addr));
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
        sta->pspoll = 0;
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
-
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
 {
        if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
 
        if (tx->flags & IEEE80211_TXRXD_TXUNICAST)
                return ieee80211_tx_h_unicast_ps_buf(tx);
@@ -428,13 +453,11 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
                return ieee80211_tx_h_multicast_ps_buf(tx);
 }
 
-
-
-
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_key *key;
+       u16 fc = tx->fc;
 
        if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
                tx->key = NULL;
@@ -443,23 +466,42 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
        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))) {
+                !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
+                !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-               return TXRX_DROP;
-       } else {
+               return TX_DROP;
+       } else
                tx->key = NULL;
-               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-       }
 
        if (tx->key) {
+               u16 ftype, stype;
+
                tx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
+
+               switch (tx->key->conf.alg) {
+               case ALG_WEP:
+                       ftype = fc & IEEE80211_FCTL_FTYPE;
+                       stype = fc & IEEE80211_FCTL_STYPE;
+
+                       if (ftype == IEEE80211_FTYPE_MGMT &&
+                           stype == IEEE80211_STYPE_AUTH)
+                               break;
+               case ALG_TKIP:
+               case ALG_CCMP:
+                       if (!WLAN_FC_DATA_PRESENT(fc))
+                               tx->key = NULL;
+                       break;
+               }
        }
 
-       return TXRX_CONTINUE;
+       if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+
+       return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
@@ -471,14 +513,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
        int frag_threshold = tx->local->fragmentation_threshold;
 
        if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED))
-               return TXRX_CONTINUE;
+               return TX_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;
+       num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
 
        frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
        if (!frags)
@@ -525,7 +567,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
        tx->u.tx.num_extra_frag = num_fragm - 1;
        tx->u.tx.extra_frag = frags;
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 
  fail:
        printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
@@ -536,14 +578,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
                kfree(frags);
        }
        I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
-       return TXRX_DROP;
+       return TX_DROP;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 {
        if (!tx->key)
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
 
        switch (tx->key->conf.alg) {
        case ALG_WEP:
@@ -556,63 +598,60 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 
        /* not reached */
        WARN_ON(1);
-       return TXRX_DROP;
+       return TX_DROP;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
 {
-       struct rate_control_extra extra;
+       struct rate_selection rsel;
+       struct ieee80211_supported_band *sband;
 
-       if (likely(!tx->u.tx.rate)) {
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = tx->u.tx.mode;
-               extra.ethertype = tx->ethertype;
+       sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
 
-               tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
-                                                     tx->skb, &extra);
-               if (unlikely(extra.probe != NULL)) {
+       if (likely(!tx->u.tx.rate)) {
+               rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+               tx->u.tx.rate = rsel.rate;
+               if (unlikely(rsel.probe)) {
                        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;
+                       tx->u.tx.control->alt_retry_rate = tx->u.tx.rate;
+                       tx->u.tx.rate = rsel.probe;
                } else
-                       tx->u.tx.control->alt_retry_rate = -1;
+                       tx->u.tx.control->alt_retry_rate = NULL;
 
                if (!tx->u.tx.rate)
-                       return TXRX_DROP;
+                       return TX_DROP;
        } else
-               tx->u.tx.control->alt_retry_rate = -1;
+               tx->u.tx.control->alt_retry_rate = NULL;
 
-       if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
-           (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
-           (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) {
+       if (tx->sdata->bss_conf.use_cts_prot &&
+           (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) {
                tx->u.tx.last_frag_rate = tx->u.tx.rate;
-               if (extra.probe)
+               if (rsel.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.rate = rsel.nonerp;
+               tx->u.tx.control->tx_rate = rsel.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;
        }
-       tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+       tx->u.tx.control->tx_rate = tx->u.tx.rate;
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_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)) {
@@ -639,16 +678,16 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
                 * frames.
                 * TODO: The last fragment could still use multiple retry
                 * rates. */
-               control->alt_retry_rate = -1;
+               control->alt_retry_rate = NULL;
        }
 
        /* 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) &&
+       if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+           (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) &&
            (tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
-           (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
+           tx->sdata->bss_conf.use_cts_prot &&
            !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
                control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
 
@@ -656,10 +695,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
         * 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->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+           tx->sdata->bss_conf.use_short_preamble &&
            (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-               tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
        }
 
        /* Setup duration field for the first fragment of the frame. Duration
@@ -672,19 +711,33 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 
        if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
            (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
-               struct ieee80211_rate *rate;
+               struct ieee80211_supported_band *sband;
+               struct ieee80211_rate *rate, *baserate;
+               int idx;
+
+               sband = tx->local->hw.wiphy->bands[
+                               tx->local->hw.conf.channel->band];
 
                /* Do not use multiple retry rates when using RTS/CTS */
-               control->alt_retry_rate = -1;
+               control->alt_retry_rate = NULL;
 
                /* 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--;
+               baserate = NULL;
 
-               control->rts_cts_rate = rate->val;
-               control->rts_rate = rate;
+               for (idx = 0; idx < sband->n_bitrates; idx++) {
+                       if (sband->bitrates[idx].bitrate > rate->bitrate)
+                               continue;
+                       if (tx->sdata->basic_rates & BIT(idx) &&
+                           (!baserate ||
+                            (baserate->bitrate < sband->bitrates[idx].bitrate)))
+                               baserate = &sband->bitrates[idx];
+               }
+
+               if (baserate)
+                       control->rts_cts_rate = baserate;
+               else
+                       control->rts_cts_rate = &sband->bitrates[0];
        }
 
        if (tx->sta) {
@@ -701,26 +754,17 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
                }
        }
 
-       /*
-        * 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;
+       return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_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;
+       struct ieee80211_rate *rate = tx->u.tx.rate;
 
        /* 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
@@ -731,9 +775,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
        /* 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))
+       if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ ||
+           (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ &&
+            rate->flags & IEEE80211_RATE_ERP_G))
                hdrtime = CHAN_UTIL_HDR_SHORT;
        else
                hdrtime = CHAN_UTIL_HDR_LONG;
@@ -747,14 +791,15 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
        else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
                load += hdrtime;
 
-       load += skb->len * tx->u.tx.rate->rate_inv;
+       /* TODO: optimise again */
+       load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
        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;
+                               tx->u.tx.rate->bitrate;
                }
        }
 
@@ -765,13 +810,12 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
                tx->sta->channel_use_raw += load;
        tx->sdata->channel_use_raw += load;
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
-/* TODO: implement register/unregister functions for adding TX/RX handlers
- * into ordered list */
 
-ieee80211_tx_handler ieee80211_tx_handlers[] =
+typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *);
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
        ieee80211_tx_h_check_assoc,
        ieee80211_tx_h_sequence,
@@ -792,7 +836,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] =
  * deal with packet injection down monitor interface
  * with Radiotap Header -- only called for monitor mode interface
  */
-static ieee80211_txrx_result
+static ieee80211_tx_result
 __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
                              struct sk_buff *skb)
 {
@@ -807,10 +851,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
        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;
+       struct ieee80211_supported_band *sband;
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
        struct ieee80211_tx_control *control = tx->u.tx.control;
 
+       sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+
        control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
        tx->flags |= IEEE80211_TXRXD_TX_INJECTED;
        tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
@@ -843,10 +889,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
                         * 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];
+                       for (i = 0; i < sband->n_bitrates; i++) {
+                               struct ieee80211_rate *r;
 
-                               if (r->rate == target_rate) {
+                               r = &sband->bitrates[i];
+
+                               if (r->bitrate == target_rate) {
                                        tx->u.tx.rate = r;
                                        break;
                                }
@@ -861,9 +909,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
                        control->antenna_sel_tx = (*iterator.this_arg) + 1;
                        break;
 
+#if 0
                case IEEE80211_RADIOTAP_DBM_TX_POWER:
                        control->power_level = *iterator.this_arg;
                        break;
+#endif
 
                case IEEE80211_RADIOTAP_FLAGS:
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
@@ -875,7 +925,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
                                 * on transmission
                                 */
                                if (skb->len < (iterator.max_length + FCS_LEN))
-                                       return TXRX_DROP;
+                                       return TX_DROP;
 
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
@@ -898,7 +948,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
        }
 
        if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
-               return TXRX_DROP;
+               return TX_DROP;
 
        /*
         * remove the radiotap header
@@ -907,13 +957,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
         */
        skb_pull(skb, iterator.max_length);
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
 /*
  * initialises @tx
  */
-static ieee80211_txrx_result
+static ieee80211_tx_result
 __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
                       struct sk_buff *skb,
                       struct net_device *dev,
@@ -922,7 +972,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
        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;
 
@@ -940,9 +989,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 
        /* 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;
+       if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
+               if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+                       return TX_DROP;
 
                /*
                 * __ieee80211_parse_tx_radiotap has now removed
@@ -987,12 +1036,10 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
        }
        control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
 
-       return res;
+       return TX_CONTINUE;
 }
 
-/* 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,
@@ -1004,7 +1051,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
        struct net_device *dev;
 
        pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       dev = dev_get_by_index(pkt_data->ifindex);
+       dev = dev_get_by_index(&init_net, pkt_data->ifindex);
        if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
                dev_put(dev);
                dev = NULL;
@@ -1013,6 +1060,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
                return -ENODEV;
        /* initialises tx with control */
        __ieee80211_tx_prepare(tx, skb, dev, control);
+       dev_put(dev);
        return 0;
 }
 
@@ -1047,8 +1095,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
                        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;
+                               control->tx_rate = tx->u.tx.last_frag_rate;
+
                                if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG)
                                        control->flags |=
                                                IEEE80211_TXCTL_RATE_CTRL_PROBE;
@@ -1082,7 +1130,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        struct sta_info *sta;
        ieee80211_tx_handler *handler;
        struct ieee80211_txrx_data tx;
-       ieee80211_txrx_result res = TXRX_DROP, res_prepare;
+       ieee80211_tx_result res = TX_DROP, res_prepare;
        int ret, i;
 
        WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1095,7 +1143,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        /* initialises tx */
        res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
 
-       if (res_prepare == TXRX_DROP) {
+       if (res_prepare == TX_DROP) {
                dev_kfree_skb(skb);
                return 0;
        }
@@ -1107,12 +1155,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        rcu_read_lock();
 
        sta = tx.sta;
-       tx.u.tx.mode = local->hw.conf.mode;
+       tx.u.tx.channel = local->hw.conf.channel;
 
-       for (handler = local->tx_handlers; *handler != NULL;
+       for (handler = ieee80211_tx_handlers; *handler != NULL;
             handler++) {
                res = (*handler)(&tx);
-               if (res != TXRX_CONTINUE)
+               if (res != TX_CONTINUE)
                        break;
        }
 
@@ -1121,12 +1169,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        if (sta)
                sta_info_put(sta);
 
-       if (unlikely(res == TXRX_DROP)) {
+       if (unlikely(res == TX_DROP)) {
                I802_DEBUG_INC(local->tx_handlers_drop);
                goto drop;
        }
 
-       if (unlikely(res == TXRX_QUEUED)) {
+       if (unlikely(res == TX_QUEUED)) {
                I802_DEBUG_INC(local->tx_handlers_queued);
                rcu_read_unlock();
                return 0;
@@ -1144,7 +1192,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                        } 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);
@@ -1181,7 +1228,6 @@ retry:
                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);
@@ -1219,7 +1265,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
        memset(&control, 0, sizeof(struct ieee80211_tx_control));
 
        if (pkt_data->ifindex)
-               odev = dev_get_by_index(pkt_data->ifindex);
+               odev = dev_get_by_index(&init_net, pkt_data->ifindex);
        if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
                dev_put(odev);
                odev = NULL;
@@ -1243,14 +1289,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
                }
        }
 
-       control.ifindex = odev->ifindex;
-       control.type = osdata->type;
+       control.vif = &osdata->vif;
+       control.type = osdata->vif.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;
+       if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
+               control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
+       if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
+               control.flags |= IEEE80211_TXCTL_AMPDU;
        control.queue = pkt_data->queue;
 
        ret = ieee80211_tx(odev, skb, &control);
@@ -1343,6 +1393,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
        struct sta_info *sta;
+       u32 sta_flags = 0;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (unlikely(skb->len < ETH_HLEN)) {
@@ -1358,10 +1409,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        /* 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) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_AP:
        case IEEE80211_IF_TYPE_VLAN:
                fc |= IEEE80211_FCTL_FROMDS;
@@ -1400,14 +1450,47 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                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;
+       /*
+        * There's no need to try to look up the destination
+        * if it is a multicast address (which can only happen
+        * in AP mode)
+        */
+       if (!is_multicast_ether_addr(hdr.addr1)) {
+               sta = sta_info_get(local, hdr.addr1);
+               if (sta) {
+                       sta_flags = sta->flags;
+                       sta_info_put(sta);
                }
-               sta_info_put(sta);
+       }
+
+       /* receiver is QoS enabled, use a QoS type frame */
+       if (sta_flags & WLAN_STA_WME) {
+               fc |= IEEE80211_STYPE_QOS_DATA;
+               hdrlen += 2;
+       }
+
+       /*
+        * Drop unicast frames to unauthorised stations unless they are
+        * EAPOL frames from the local station.
+        */
+       if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
+                    !(sta_flags & WLAN_STA_AUTHORIZED) &&
+                    !(ethertype == ETH_P_PAE &&
+                      compare_ether_addr(dev->dev_addr,
+                                         skb->data + ETH_ALEN) == 0))) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               DECLARE_MAC_BUF(mac);
+
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: dropped frame to %s"
+                              " (unauthorized port)\n", dev->name,
+                              print_mac(mac, hdr.addr1));
+#endif
+
+               I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
+
+               ret = 0;
+               goto fail;
        }
 
        hdr.frame_control = cpu_to_le16(fc);
@@ -1498,6 +1581,8 @@ int ieee80211_subif_start_xmit(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 = dev->ifindex;
+       if (ethertype == ETH_P_PAE)
+               pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 
        skb->dev = local->mdev;
        dev->stats.tx_packets++;
@@ -1522,64 +1607,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *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)
@@ -1619,7 +1646,6 @@ void ieee80211_tx_pending(unsigned long data)
                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)
@@ -1648,7 +1674,8 @@ void ieee80211_tx_pending(unsigned long data)
 
 static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
                                     struct ieee80211_if_ap *bss,
-                                    struct sk_buff *skb)
+                                    struct sk_buff *skb,
+                                    struct beacon_data *beacon)
 {
        u8 *pos, *tim;
        int aid0 = 0;
@@ -1664,7 +1691,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
                                          IEEE80211_MAX_AID+1);
 
        if (bss->dtim_count == 0)
-               bss->dtim_count = bss->dtim_period - 1;
+               bss->dtim_count = beacon->dtim_period - 1;
        else
                bss->dtim_count--;
 
@@ -1672,7 +1699,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
        *pos++ = WLAN_EID_TIM;
        *pos++ = 4;
        *pos++ = bss->dtim_count;
-       *pos++ = bss->dtim_period;
+       *pos++ = beacon->dtim_period;
 
        if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
                aid0 = 1;
@@ -1710,7 +1737,8 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
        read_unlock_bh(&local->sta_lock);
 }
 
-struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_tx_control *control)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1718,81 +1746,81 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
        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);
-       }
+       struct rate_selection rsel;
+       struct beacon_data *beacon;
+       struct ieee80211_supported_band *sband;
 
-       if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
-           !ap->beacon_head) {
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       rcu_read_lock();
+
+       sdata = vif_to_sdata(vif);
+       bdev = sdata->dev;
+       ap = &sdata->u.ap;
+
+       beacon = rcu_dereference(ap->beacon);
+
+       if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) {
 #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");
+                       printk(KERN_DEBUG "no beacon data avail for %s\n",
+                              bdev->name);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-               return NULL;
+               skb = NULL;
+               goto out;
        }
 
-       /* 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 */);
+       /* headroom, head length, tail length and maximum TIM length */
+       skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+                           beacon->tail_len + 256);
        if (!skb)
-               return NULL;
+               goto out;
 
        skb_reserve(skb, local->tx_headroom);
-       memcpy(skb_put(skb, bh_len), b_head, bh_len);
+       memcpy(skb_put(skb, beacon->head_len), beacon->head,
+              beacon->head_len);
 
        ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
 
-       ieee80211_beacon_add_tim(local, ap, skb);
+       ieee80211_beacon_add_tim(local, ap, skb, beacon);
 
-       if (b_tail) {
-               memcpy(skb_put(skb, bt_len), b_tail, bt_len);
-       }
+       if (beacon->tail)
+               memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
+                      beacon->tail_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) {
+               rate_control_get_rate(local->mdev, sband, skb, &rsel);
+               if (!rsel.rate) {
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-                                      "found\n", wiphy_name(local->hw.wiphy));
+                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+                                      "no rate found\n",
+                                      wiphy_name(local->hw.wiphy));
                        }
                        dev_kfree_skb(skb);
-                       return NULL;
+                       skb = NULL;
+                       goto out;
                }
 
-               control->tx_rate =
-                       ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
+               control->vif = vif;
+               control->tx_rate = rsel.rate;
+               if (sdata->bss_conf.use_short_preamble &&
+                   rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+                       control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
                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++;
+
+ out:
+       rcu_read_unlock();
        return skb;
 }
 EXPORT_SYMBOL(ieee80211_beacon_get);
 
-void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
+void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
                       const struct ieee80211_tx_control *frame_txctl,
                       struct ieee80211_rts *rts)
@@ -1802,13 +1830,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
 
        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);
+       rts->duration = ieee80211_rts_duration(hw, vif, 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,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                             const void *frame, size_t frame_len,
                             const struct ieee80211_tx_control *frame_txctl,
                             struct ieee80211_cts *cts)
@@ -1818,13 +1847,15 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
 
        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);
+       cts->duration = ieee80211_ctstoself_duration(hw, vif,
+                                                    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,
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
                          struct ieee80211_tx_control *control)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1832,19 +1863,28 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
        struct sta_info *sta;
        ieee80211_tx_handler *handler;
        struct ieee80211_txrx_data tx;
-       ieee80211_txrx_result res = TXRX_DROP;
+       ieee80211_tx_result res = TX_DROP;
        struct net_device *bdev;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_ap *bss = NULL;
+       struct beacon_data *beacon;
 
-       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)
+       sdata = vif_to_sdata(vif);
+       bdev = sdata->dev;
+
+
+       if (!bss)
+               return NULL;
+
+       rcu_read_lock();
+       beacon = rcu_dereference(bss->beacon);
+
+       if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon ||
+           !beacon->head) {
+               rcu_read_unlock();
                return NULL;
+       }
+       rcu_read_unlock();
 
        if (bss->dtim_count != 0)
                return NULL; /* send buffered bc/mc only after DTIM beacon */
@@ -1871,21 +1911,20 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
        }
        sta = tx.sta;
        tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
-       tx.u.tx.mode = local->hw.conf.mode;
+       tx.u.tx.channel = local->hw.conf.channel;
 
-       for (handler = local->tx_handlers; *handler != NULL; handler++) {
+       for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
                res = (*handler)(&tx);
-               if (res == TXRX_DROP || res == TXRX_QUEUED)
+               if (res == TX_DROP || res == TX_QUEUED)
                        break;
        }
-       dev_put(tx.dev);
        skb = tx.skb; /* handlers are allowed to change skb */
 
-       if (res == TXRX_DROP) {
+       if (res == TX_DROP) {
                I802_DEBUG_INC(local->tx_handlers_drop);
                dev_kfree_skb(skb);
                skb = NULL;
-       } else if (res == TXRX_QUEUED) {
+       } else if (res == TX_QUEUED) {
                I802_DEBUG_INC(local->tx_handlers_queued);
                skb = NULL;
        }
index 27203f1b95ddc95f498634eec608c7e9fc9e11fe..f64804fed0a9ca27bb9dcd8f1b5913b673ddeda8 100644 (file)
@@ -20,7 +20,9 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/bitmap.h>
+#include <net/net_namespace.h>
 #include <net/cfg80211.h>
+#include <net/rtnetlink.h>
 
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
@@ -38,108 +40,22 @@ const unsigned char rfc1042_header[] =
 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)
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+                       enum ieee80211_if_types type)
 {
        u16 fc;
 
-       if (len < 24)
+        /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
+       if (len < 16)
                return NULL;
 
        fc = le16_to_cpu(hdr->frame_control);
 
        switch (fc & IEEE80211_FCTL_FTYPE) {
        case IEEE80211_FTYPE_DATA:
+               if (len < 24) /* drop incorrect hdr len (data) */
+                       return NULL;
                switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
                case IEEE80211_FCTL_TODS:
                        return hdr->addr1;
@@ -152,10 +68,24 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
                }
                break;
        case IEEE80211_FTYPE_MGMT:
+               if (len < 24) /* drop incorrect hdr len (mgmt) */
+                       return NULL;
                return hdr->addr3;
        case IEEE80211_FTYPE_CTL:
                if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
                        return hdr->addr1;
+               else if ((fc & IEEE80211_FCTL_STYPE) ==
+                                               IEEE80211_STYPE_BACK_REQ) {
+                       switch (type) {
+                       case IEEE80211_IF_TYPE_STA:
+                               return hdr->addr2;
+                       case IEEE80211_IF_TYPE_AP:
+                       case IEEE80211_IF_TYPE_VLAN:
+                               return hdr->addr1;
+                       default:
+                               return NULL;
+                       }
+               }
                else
                        return NULL;
        }
@@ -216,31 +146,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 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;
@@ -271,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
         * DIV_ROUND_UP() operations.
         */
 
-       if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+       if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
                /*
                 * OFDM:
                 *
@@ -311,120 +216,92 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 }
 
 /* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
-                                       size_t frame_len, int rate)
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
+                                       size_t frame_len,
+                                       struct ieee80211_rate *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;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        u16 dur;
        int erp;
 
-       if (unlikely(!bdev))
-               return 0;
+       erp = 0;
+       if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               erp = rate->flags & IEEE80211_RATE_ERP_G;
 
-       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);
+       dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
+                                      sdata->bss_conf.use_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,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, 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;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       bool short_preamble;
        int erp;
        u16 dur;
 
-       if (unlikely(!bdev))
-               return 0;
+       short_preamble = sdata->bss_conf.use_short_preamble;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-       short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
+       rate = frame_txctl->rts_cts_rate;
 
-       rate = frame_txctl->rts_rate;
-       erp = !!(rate->flags & IEEE80211_RATE_ERP);
+       erp = 0;
+       if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               erp = rate->flags & IEEE80211_RATE_ERP_G;
 
        /* CTS duration */
-       dur = ieee80211_frame_duration(local, 10, rate->rate,
+       dur = ieee80211_frame_duration(local, 10, rate->bitrate,
                                       erp, short_preamble);
        /* Data frame duration */
-       dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+       dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
                                        erp, short_preamble);
        /* ACK duration */
-       dur += ieee80211_frame_duration(local, 10, rate->rate,
+       dur += ieee80211_frame_duration(local, 10, rate->bitrate,
                                        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,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
                                    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;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       bool short_preamble;
        int erp;
        u16 dur;
 
-       if (unlikely(!bdev))
-               return 0;
+       short_preamble = sdata->bss_conf.use_short_preamble;
 
-       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);
+       rate = frame_txctl->rts_cts_rate;
+       erp = 0;
+       if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               erp = rate->flags & IEEE80211_RATE_ERP_G;
 
        /* Data frame duration */
-       dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+       dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
                                       erp, short_preamble);
        if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
                /* ACK duration */
-               dur += ieee80211_frame_duration(local, 10, rate->rate,
+               dur += ieee80211_frame_duration(local, 10, rate->bitrate,
                                                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);
@@ -483,3 +360,37 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
                ieee80211_wake_queue(hw, i);
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
+
+void ieee80211_iterate_active_interfaces(
+       struct ieee80211_hw *hw,
+       void (*iterator)(void *data, u8 *mac,
+                        struct ieee80211_vif *vif),
+       void *data)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               switch (sdata->vif.type) {
+               case IEEE80211_IF_TYPE_INVALID:
+               case IEEE80211_IF_TYPE_MNTR:
+               case IEEE80211_IF_TYPE_VLAN:
+                       continue;
+               case IEEE80211_IF_TYPE_AP:
+               case IEEE80211_IF_TYPE_STA:
+               case IEEE80211_IF_TYPE_IBSS:
+               case IEEE80211_IF_TYPE_WDS:
+                       break;
+               }
+               if (sdata->dev == local->mdev)
+                       continue;
+               if (netif_running(sdata->dev))
+                       iterator(data, sdata->dev->dev_addr,
+                                &sdata->vif);
+       }
+
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
index 6675261e958f41abb0fc23a8bf3f3178e0364c8f..a33ef5cfa9adb42826426ee646eef0d5c81c658c 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
        *icv = cpu_to_le32(~crc32_le(~0, data, data_len));
 
        crypto_blkcipher_setkey(tfm, rc4key, klen);
-       sg.page = virt_to_page(data);
-       sg.offset = offset_in_page(data);
-       sg.length = data_len + WEP_ICV_LEN;
+       sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
        crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
 }
 
@@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
        __le32 crc;
 
        crypto_blkcipher_setkey(tfm, rc4key, klen);
-       sg.page = virt_to_page(data);
-       sg.offset = offset_in_page(data);
-       sg.length = data_len + WEP_ICV_LEN;
+       sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
        crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
 
        crc = cpu_to_le32(~crc32_le(~0, data, data_len));
@@ -269,7 +265,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
        if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
                                       skb->data + hdrlen + WEP_IV_LEN,
                                       len)) {
-               printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
                ret = -1;
        }
 
@@ -308,20 +305,22 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
        return NULL;
 }
 
-ieee80211_txrx_result
+ieee80211_rx_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;
+               return RX_CONTINUE;
 
        if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
                if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+#ifdef CONFIG_MAC80211_DEBUG
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
                                       "failed\n", rx->dev->name);
-                       return TXRX_DROP;
+#endif /* CONFIG_MAC80211_DEBUG */
+                       return RX_DROP_UNUSABLE;
                }
        } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
                ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
@@ -329,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
                skb_trim(rx->skb, rx->skb->len - 4);
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
 static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
@@ -347,26 +346,16 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
        return 0;
 }
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc;
-
-       fc = le16_to_cpu(hdr->frame_control);
-
-       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;
-
        tx->u.tx.control->iv_len = WEP_IV_LEN;
        tx->u.tx.control->icv_len = WEP_ICV_LEN;
        ieee80211_tx_set_iswep(tx);
 
        if (wep_encrypt_skb(tx, tx->skb) < 0) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
-               return TXRX_DROP;
+               return TX_DROP;
        }
 
        if (tx->u.tx.extra_frag) {
@@ -375,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
                        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 TX_DROP;
                        }
                }
        }
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
index 785fbb4e0dd70d869777b5ecb38d9cbf958ce8f9..43aef50cd0d6e120260c6d39cd8a9f09f39bdd22 100644 (file)
@@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_key *key);
 u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
 
 #endif /* WEP_H */
index 5b8a157975a35dd452bc6e03e17f5dafcae09788..7bbc79371dafd2065a26f25db57fadc26d72dc8f 100644 (file)
 #include "wme.h"
 
 /* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 8
+#define TC_80211_MAX_QUEUES 16
+
+const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 struct ieee80211_sched_data
 {
+       unsigned long qdisc_pool;
        struct tcf_proto *filter_list;
        struct Qdisc *queues[TC_80211_MAX_QUEUES];
        struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
 };
 
+static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
 
 /* given a data frame determine the 802.1p/1d tag to use */
 static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
@@ -54,12 +58,12 @@ static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
                return skb->priority - 256;
 
        /* check there is a valid IP header present */
-       offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */;
-       if (skb->protocol != __constant_htons(ETH_P_IP) ||
-           skb->len < offset + sizeof(*ip))
+       offset = ieee80211_get_hdrlen_from_skb(skb);
+       if (skb->len < offset + sizeof(llc_ip_hdr) + sizeof(*ip) ||
+           memcmp(skb->data + offset, llc_ip_hdr, sizeof(llc_ip_hdr)))
                return 0;
 
-       ip = (struct iphdr *) (skb->data + offset);
+       ip = (struct iphdr *) (skb->data + offset + sizeof(llc_ip_hdr));
 
        dscp = ip->tos & 0xfc;
        if (dscp & 0x1c)
@@ -97,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        unsigned short fc = le16_to_cpu(hdr->frame_control);
        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 */
        if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
@@ -145,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
        unsigned short fc = le16_to_cpu(hdr->frame_control);
        struct Qdisc *qdisc;
        int err, queue;
+       struct sta_info *sta;
+       u8 tid;
 
        if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
-               skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+               queue = pkt_data->queue;
+               sta = sta_info_get(local, hdr->addr1);
+               tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
+               if (sta) {
+                       int ampdu_queue = sta->tid_to_tx_q[tid];
+                       if ((ampdu_queue < local->hw.queues) &&
+                           test_bit(ampdu_queue, &q->qdisc_pool)) {
+                               queue = ampdu_queue;
+                               pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+                       } else {
+                               pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+                       }
+                       sta_info_put(sta);
+               }
+               skb_queue_tail(&q->requeued[queue], skb);
                qd->q.qlen++;
                return 0;
        }
@@ -158,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
         */
        if (WLAN_FC_IS_QOS_DATA(fc)) {
                u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
-               u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+               u8 ack_policy = 0;
+               tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
                if (local->wifi_wme_noack_test)
-                       qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+                       ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
                                        QOS_CONTROL_ACK_POLICY_SHIFT;
                /* qos header is 2 bytes, second reserved */
-               *p = qos_hdr;
+               *p = ack_policy | tid;
                p++;
                *p = 0;
+
+               sta = sta_info_get(local, hdr->addr1);
+               if (sta) {
+                       int ampdu_queue = sta->tid_to_tx_q[tid];
+                       if ((ampdu_queue < local->hw.queues) &&
+                               test_bit(ampdu_queue, &q->qdisc_pool)) {
+                               queue = ampdu_queue;
+                               pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+                       } else {
+                               pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+                       }
+                       sta_info_put(sta);
+               }
        }
 
        if (unlikely(queue >= local->hw.queues)) {
@@ -183,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
                        kfree_skb(skb);
                        err = NET_XMIT_DROP;
        } else {
+               tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
                pkt_data->queue = (unsigned int) queue;
                qdisc = q->queues[queue];
                err = qdisc->enqueue(skb, qdisc);
@@ -234,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
        /* check all the h/w queues in numeric/priority order */
        for (queue = 0; queue < hw->queues; queue++) {
                /* see if there is room in this hardware queue */
-               if (test_bit(IEEE80211_LINK_STATE_XOFF,
-                            &local->state[queue]) ||
-                   test_bit(IEEE80211_LINK_STATE_PENDING,
-                            &local->state[queue]))
+               if ((test_bit(IEEE80211_LINK_STATE_XOFF,
+                               &local->state[queue])) ||
+                   (test_bit(IEEE80211_LINK_STATE_PENDING,
+                               &local->state[queue])) ||
+                        (!test_bit(queue, &q->qdisc_pool)))
                        continue;
 
                /* there is space - try and get a frame */
@@ -359,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
                }
        }
 
+       /* reserve all legacy QoS queues */
+       for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+               set_bit(i, &q->qdisc_pool);
+
        return err;
 }
 
@@ -604,3 +643,80 @@ void ieee80211_wme_unregister(void)
 {
        unregister_qdisc(&wme_qdisc_ops);
 }
+
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+                       struct sta_info *sta, u16 tid)
+{
+       int i;
+       struct ieee80211_sched_data *q =
+                       qdisc_priv(local->mdev->qdisc_sleeping);
+       DECLARE_MAC_BUF(mac);
+
+       /* prepare the filter and save it for the SW queue
+        * matching the recieved HW queue */
+
+       /* try to get a Qdisc from the pool */
+       for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+               if (!test_and_set_bit(i, &q->qdisc_pool)) {
+                       ieee80211_stop_queue(local_to_hw(local), i);
+                       sta->tid_to_tx_q[tid] = i;
+
+                       /* IF there are already pending packets
+                        * on this tid first we need to drain them
+                        * on the previous queue
+                        * since HT is strict in order */
+#ifdef CONFIG_MAC80211_HT_DEBUG
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "allocated aggregation queue"
+                                       " %d tid %d addr %s pool=0x%lX\n",
+                                       i, tid, print_mac(mac, sta->addr),
+                                       q->qdisc_pool);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+                       return 0;
+               }
+
+       return -EAGAIN;
+}
+
+/**
+ * the caller needs to hold local->mdev->queue_lock
+ */
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+                                  struct sta_info *sta, u16 tid,
+                                  u8 requeue)
+{
+       struct ieee80211_sched_data *q =
+               qdisc_priv(local->mdev->qdisc_sleeping);
+       int agg_queue = sta->tid_to_tx_q[tid];
+
+       /* return the qdisc to the pool */
+       clear_bit(agg_queue, &q->qdisc_pool);
+       sta->tid_to_tx_q[tid] = local->hw.queues;
+
+       if (requeue)
+               ieee80211_requeue(local, agg_queue);
+       else
+               q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
+}
+
+void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+       struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
+       struct ieee80211_sched_data *q = qdisc_priv(root_qd);
+       struct Qdisc *qdisc = q->queues[queue];
+       struct sk_buff *skb = NULL;
+       u32 len = qdisc->q.qlen;
+
+       if (!qdisc || !qdisc->dequeue)
+               return;
+
+       printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
+       for (len = qdisc->q.qlen; len > 0; len--) {
+               skb = qdisc->dequeue(qdisc);
+               root_qd->q.qlen--;
+               /* packet will be classified again and */
+               /* skb->packet_data->queue will be overridden if needed */
+               if (skb)
+                       wme_qdiscop_enqueue(skb, root_qd);
+       }
+}
index 76c713a6450c37290f0ba521cbe2e212e06bc514..fcc6b05508ccf06eeeb94c4ff7869c148b7168f4 100644 (file)
@@ -24,6 +24,8 @@
 
 #define QOS_CONTROL_TAG1D_MASK 0x07
 
+extern const int ieee802_1d_to_ac[8];
+
 static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 {
        return (fc & 0x8C) == 0x88;
@@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 #ifdef CONFIG_NET_SCHED
 void ieee80211_install_qdisc(struct net_device *dev);
 int ieee80211_qdisc_installed(struct net_device *dev);
-
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+                              struct sta_info *sta, u16 tid);
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+                                  struct sta_info *sta, u16 tid,
+                                  u8 requeue);
+void ieee80211_requeue(struct ieee80211_local *local, int queue);
 int ieee80211_wme_register(void);
 void ieee80211_wme_unregister(void);
 #else
@@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev)
 {
        return 0;
 }
-
+static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+                                            struct sta_info *sta, u16 tid)
+{
+       return -EAGAIN;
+}
+static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+                                                struct sta_info *sta, u16 tid,
+                                                u8 requeue)
+{
+}
+static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+}
 static inline int ieee80211_wme_register(void)
 {
        return 0;
index 0b32ab64ebdf2f5df7d0db5e31505d2e4389e41d..b35e51c6ce0c4e8e7341158b05d4740d039ce2f3 100644 (file)
@@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 {
        u8 *data, *sa, *da, *key, *mic, qos_tid;
@@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 
        if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
            !WLAN_FC_DATA_PRESENT(fc))
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
 
        if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
-               return TXRX_DROP;
+               return TX_DROP;
 
        if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
            !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
@@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
            !wpa_test) {
                /* hwaccel - with no need for preallocated room for Michael MIC
                 */
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
        }
 
        if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
@@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
                                              GFP_ATOMIC))) {
                        printk(KERN_DEBUG "%s: failed to allocate more memory "
                               "for Michael MIC\n", tx->dev->name);
-                       return TXRX_DROP;
+                       return TX_DROP;
                }
        }
 
@@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
        mic = skb_put(skb, MICHAEL_MIC_LEN);
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 {
        u8 *data, *sa, *da, *key = NULL, qos_tid;
@@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
        u8 mic[MICHAEL_MIC_LEN];
        struct sk_buff *skb = rx->skb;
        int authenticator = 1, wpa_test = 0;
+       DECLARE_MAC_BUF(mac);
 
        fc = rx->fc;
 
@@ -139,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
         * No way to verify the MIC if the hardware stripped it
         */
        if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
            !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
            || data_len < MICHAEL_MIC_LEN)
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
 
        data_len -= MICHAEL_MIC_LEN;
 
@@ -161,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
        michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
        if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
                if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
 
                printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
-                      MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
+                      "%s\n", rx->dev->name, print_mac(mac, sa));
 
                mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
                                                (void *) skb->data);
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
        }
 
        /* remove Michael MIC from payload */
@@ -178,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
        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;
+       return RX_CONTINUE;
 }
 
 
@@ -241,19 +242,12 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc;
        struct sk_buff *skb = tx->skb;
        int wpa_test = 0, test = 0;
 
-       fc = le16_to_cpu(hdr->frame_control);
-
-       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);
@@ -263,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
            !wpa_test) {
                /* hwaccel - with no need for preallocated room for IV/ICV */
                tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
        }
 
        if (tkip_encrypt_skb(tx, skb, test) < 0)
-               return TXRX_DROP;
+               return TX_DROP;
 
        if (tx->u.tx.extra_frag) {
                int i;
                for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
                        if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
                            < 0)
-                               return TXRX_DROP;
+                               return TX_DROP;
                }
        }
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -290,15 +284,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
        int hdrlen, res, hwaccel = 0, wpa_test = 0;
        struct ieee80211_key *key = rx->key;
        struct sk_buff *skb = rx->skb;
+       DECLARE_MAC_BUF(mac);
 
        fc = le16_to_cpu(hdr->frame_control);
        hdrlen = ieee80211_get_hdrlen(fc);
 
        if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        if (!rx->sta || skb->len - hdrlen < 12)
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
 
        if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
                if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
@@ -307,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
                         * replay protection, and stripped the ICV/IV so
                         * we cannot do any checks here.
                         */
-                       return TXRX_CONTINUE;
+                       return RX_CONTINUE;
                }
 
                /* let TKIP code verify IV, but skip decryption */
@@ -321,10 +316,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
                                          &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",
-                      rx->dev->name, MAC_ARG(rx->sta->addr), res);
-               return TXRX_DROP;
+#ifdef CONFIG_MAC80211_DEBUG
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: TKIP decrypt failed for RX "
+                              "frame from %s (res=%d)\n", rx->dev->name,
+                              print_mac(mac, rx->sta->addr), res);
+#endif /* CONFIG_MAC80211_DEBUG */
+               return RX_DROP_UNUSABLE;
        }
 
        /* Trim ICV */
@@ -334,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
        memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
        skb_pull(skb, TKIP_IV_LEN);
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
 
@@ -493,19 +491,12 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc;
        struct sk_buff *skb = tx->skb;
        int test = 0;
 
-       fc = le16_to_cpu(hdr->frame_control);
-
-       if (!WLAN_FC_DATA_PRESENT(fc))
-               return TXRX_CONTINUE;
-
        tx->u.tx.control->icv_len = CCMP_MIC_LEN;
        tx->u.tx.control->iv_len = CCMP_HDR_LEN;
        ieee80211_tx_set_iswep(tx);
@@ -515,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
                /* hwaccel - with no need for preallocated room for CCMP "
                 * header or MIC fields */
                tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-               return TXRX_CONTINUE;
+               return TX_CONTINUE;
        }
 
        if (ccmp_encrypt_skb(tx, skb, test) < 0)
-               return TXRX_DROP;
+               return TX_DROP;
 
        if (tx->u.tx.extra_frag) {
                int i;
                for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
                        if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
                            < 0)
-                               return TXRX_DROP;
+                               return TX_DROP;
                }
        }
 
-       return TXRX_CONTINUE;
+       return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -544,35 +535,37 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
        struct sk_buff *skb = rx->skb;
        u8 pn[CCMP_PN_LEN];
        int data_len;
+       DECLARE_MAC_BUF(mac);
 
        fc = le16_to_cpu(hdr->frame_control);
        hdrlen = ieee80211_get_hdrlen(fc);
 
        if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
        if (!rx->sta || data_len < 0)
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
 
        if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
            (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        (void) ccmp_hdr2pn(pn, skb->data + hdrlen);
 
        if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
 #ifdef CONFIG_MAC80211_DEBUG
                u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+
                printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
-                      MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
+                      "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
                       "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
-                      MAC_ARG(rx->sta->addr),
+                      print_mac(mac, rx->sta->addr),
                       pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
                       ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
 #endif /* CONFIG_MAC80211_DEBUG */
                key->u.ccmp.replays++;
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
        }
 
        if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
@@ -590,10 +583,13 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
                            skb->data + hdrlen + CCMP_HDR_LEN, data_len,
                            skb->data + skb->len - CCMP_MIC_LEN,
                            skb->data + hdrlen + CCMP_HDR_LEN)) {
-                       printk(KERN_DEBUG "%s: CCMP decrypt failed for RX "
-                              "frame from " MAC_FMT "\n", rx->dev->name,
-                              MAC_ARG(rx->sta->addr));
-                       return TXRX_DROP;
+#ifdef CONFIG_MAC80211_DEBUG
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: CCMP decrypt failed "
+                                      "for RX frame from %s\n", rx->dev->name,
+                                      print_mac(mac, rx->sta->addr));
+#endif /* CONFIG_MAC80211_DEBUG */
+                       return RX_DROP_UNUSABLE;
                }
        }
 
@@ -604,6 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
        memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
        skb_pull(skb, CCMP_HDR_LEN);
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
-
index 49d80cf0cd7569fb5f409121f017b185f0e76bdf..16e4dba4aa700f09655577c9d3cd4b7a05945a51 100644 (file)
 #include <linux/types.h>
 #include "ieee80211_i.h"
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx);
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx);
 
 #endif /* WPA_H */
index 6291f13bba0901a56618d0857c7a7f8a335ef55c..79270903bda6f2bb02553baff2b71137d87bdfd2 100644 (file)
@@ -3,16 +3,16 @@ config CFG80211
 
 config NL80211
        bool "nl80211 new netlink interface support"
-       depends CFG80211
+       depends on CFG80211
        default y
        ---help---
-         This option turns on the new netlink interface
-         (nl80211) support in cfg80211.
+         This option turns on the new netlink interface
+         (nl80211) support in cfg80211.
 
-         If =n, drivers using mac80211 will be configured via
-         wireless extension support provided by that subsystem.
+         If =n, drivers using mac80211 will be configured via
+         wireless extension support provided by that subsystem.
 
-         If unsure, say Y.
+         If unsure, say Y.
 
 config WIRELESS_EXT
        bool "Wireless extensions"
index 5664c2cfd7600323d74a85d36b5ba5dcf225c270..b9f943c45f3b2584e3462d61af9cd1d799cc6579 100644 (file)
@@ -1,4 +1,5 @@
+obj-$(CONFIG_WIRELESS_EXT) += wext.o
 obj-$(CONFIG_CFG80211) += cfg80211.o
 
-cfg80211-y += core.o sysfs.o radiotap.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
index 35b79bee3a628ac890db77694db85dc6d9121e17..80afacdae46c5540b0a49b01708da4c1f7b64142 100644 (file)
@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_info *info)
 
        if (info->attrs[NL80211_ATTR_IFINDEX]) {
                ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-               dev = dev_get_by_index(ifindex);
+               dev = dev_get_by_index(&init_net, ifindex);
                if (dev) {
                        if (dev->ieee80211_ptr)
                                byifidx =
@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
        struct net_device *dev;
 
        mutex_lock(&cfg80211_drv_mutex);
-       dev = dev_get_by_index(ifindex);
+       dev = dev_get_by_index(&init_net, ifindex);
        if (!dev)
                goto out;
        if (dev->ieee80211_ptr) {
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
        struct cfg80211_registered_device *drv;
        int alloc_size;
 
+       WARN_ON(!ops->add_key && ops->del_key);
+       WARN_ON(ops->add_key && !ops->del_key);
+
        alloc_size = sizeof(*drv) + sizeof_priv;
 
        drv = kzalloc(alloc_size, GFP_KERNEL);
@@ -229,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy)
 {
        struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
        int res;
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       bool have_band = false;
+       int i;
+
+       /* sanity check supported bands/channels */
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               sband = wiphy->bands[band];
+               if (!sband)
+                       continue;
+
+               sband->band = band;
+
+               if (!sband->n_channels || !sband->n_bitrates) {
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < sband->n_channels; i++) {
+                       sband->channels[i].orig_flags =
+                               sband->channels[i].flags;
+                       sband->channels[i].orig_mag =
+                               sband->channels[i].max_antenna_gain;
+                       sband->channels[i].orig_mpwr =
+                               sband->channels[i].max_power;
+                       sband->channels[i].band = band;
+               }
+
+               have_band = true;
+       }
+
+       if (!have_band) {
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       /* check and set up bitrates */
+       ieee80211_set_bitrate_flags(wiphy);
+
+       /* set up regulatory info */
+       wiphy_update_regulatory(wiphy);
 
        mutex_lock(&cfg80211_drv_mutex);
 
index eb0f846b40dff4ba9ae6a6b741c5758023b3366b..7a02c356d63dcc2649981ee2b46c55e55174d20f 100644 (file)
@@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
 extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
                               char *newname);
 
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy);
+
 #endif /* __NET_WIRELESS_CORE_H */
index 58717f303763c7d9811a1dad762716bee8f0367f..5b3474798b8d228e6a39ffacae3961f2e76a18c7 100644 (file)
@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
                return -EINVAL;
 
        ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-       *dev = dev_get_by_index(ifindex);
+       *dev = dev_get_by_index(&init_net, ifindex);
        if (!*dev)
                return -ENODEV;
 
@@ -61,6 +61,28 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
        [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
        [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+
+       [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+
+       [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
+                                   .len = WLAN_MAX_KEY_LEN },
+       [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
+       [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+       [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
+
+       [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
+       [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
+       [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
+                                      .len = IEEE80211_MAX_DATA_LEN },
+       [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
+                                      .len = IEEE80211_MAX_DATA_LEN },
+       [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
+       [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
+       [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
+       [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
+                                              .len = NL80211_MAX_SUPP_RATES },
+       [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
+       [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
 };
 
 /* message building helper */
@@ -77,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                              struct cfg80211_registered_device *dev)
 {
        void *hdr;
+       struct nlattr *nl_bands, *nl_band;
+       struct nlattr *nl_freqs, *nl_freq;
+       struct nlattr *nl_rates, *nl_rate;
+       enum ieee80211_band band;
+       struct ieee80211_channel *chan;
+       struct ieee80211_rate *rate;
+       int i;
 
        hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
        if (!hdr)
@@ -84,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
        NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+
+       nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+       if (!nl_bands)
+               goto nla_put_failure;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               if (!dev->wiphy.bands[band])
+                       continue;
+
+               nl_band = nla_nest_start(msg, band);
+               if (!nl_band)
+                       goto nla_put_failure;
+
+               /* add frequencies */
+               nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
+               if (!nl_freqs)
+                       goto nla_put_failure;
+
+               for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
+                       nl_freq = nla_nest_start(msg, i);
+                       if (!nl_freq)
+                               goto nla_put_failure;
+
+                       chan = &dev->wiphy.bands[band]->channels[i];
+                       NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+                                   chan->center_freq);
+
+                       if (chan->flags & IEEE80211_CHAN_DISABLED)
+                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
+                       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
+                       if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
+                       if (chan->flags & IEEE80211_CHAN_RADAR)
+                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+
+                       nla_nest_end(msg, nl_freq);
+               }
+
+               nla_nest_end(msg, nl_freqs);
+
+               /* add bitrates */
+               nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+               if (!nl_rates)
+                       goto nla_put_failure;
+
+               for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
+                       nl_rate = nla_nest_start(msg, i);
+                       if (!nl_rate)
+                               goto nla_put_failure;
+
+                       rate = &dev->wiphy.bands[band]->bitrates[i];
+                       NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
+                                   rate->bitrate);
+                       if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+                               NLA_PUT_FLAG(msg,
+                                       NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
+
+                       nla_nest_end(msg, nl_rate);
+               }
+
+               nla_nest_end(msg, nl_rates);
+
+               nla_nest_end(msg, nl_band);
+       }
+       nla_nest_end(msg, nl_bands);
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -241,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
        return -ENOBUFS;
 }
 
+static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
+       [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+};
+
+static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
+{
+       struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
+       int flag;
+
+       *mntrflags = 0;
+
+       if (!nla)
+               return -EINVAL;
+
+       if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
+                            nla, mntr_flags_policy))
+               return -EINVAL;
+
+       for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
+               if (flags[flag])
+                       *mntrflags |= (1<<flag);
+
+       return 0;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
        int err, ifindex;
        enum nl80211_iftype type;
        struct net_device *dev;
+       u32 flags;
 
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
                type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -267,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        rtnl_lock();
-       err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
+       err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+                                 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+                                 &flags);
+       err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+                                           type, err ? NULL : &flags);
        rtnl_unlock();
 
  unlock:
@@ -280,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *drv;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+       u32 flags;
 
        if (!info->attrs[NL80211_ATTR_IFNAME])
                return -EINVAL;
@@ -300,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        rtnl_lock();
+       err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+                                 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+                                 &flags);
        err = drv->ops->add_virtual_intf(&drv->wiphy,
-               nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
+               nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+               type, err ? NULL : &flags);
        rtnl_unlock();
 
  unlock:
@@ -335,6 +470,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+struct get_key_cookie {
+       struct sk_buff *msg;
+       int error;
+};
+
+static void get_key_callback(void *c, struct key_params *params)
+{
+       struct get_key_cookie *cookie = c;
+
+       if (params->key)
+               NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
+                       params->key_len, params->key);
+
+       if (params->seq)
+               NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
+                       params->seq_len, params->seq);
+
+       if (params->cipher)
+               NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
+                           params->cipher);
+
+       return;
+ nla_put_failure:
+       cookie->error = 1;
+}
+
+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       u8 key_idx = 0;
+       u8 *mac_addr = NULL;
+       struct get_key_cookie cookie = {
+               .error = 0,
+       };
+       void *hdr;
+       struct sk_buff *msg;
+
+       if (info->attrs[NL80211_ATTR_KEY_IDX])
+               key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+       if (key_idx > 3)
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->get_key) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                            NL80211_CMD_NEW_KEY);
+
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto out;
+       }
+
+       cookie.msg = msg;
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+       if (mac_addr)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+       rtnl_lock();
+       err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+                               &cookie, get_key_callback);
+       rtnl_unlock();
+
+       if (err)
+               goto out;
+
+       if (cookie.error)
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       err = genlmsg_unicast(msg, info->snd_pid);
+       goto out;
+
+ nla_put_failure:
+       err = -ENOBUFS;
+       nlmsg_free(msg);
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       u8 key_idx;
+
+       if (!info->attrs[NL80211_ATTR_KEY_IDX])
+               return -EINVAL;
+
+       key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+       if (key_idx > 3)
+               return -EINVAL;
+
+       /* currently only support setting default key */
+       if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+               return -EINVAL;
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->set_default_key) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       struct key_params params;
+       u8 key_idx = 0;
+       u8 *mac_addr = NULL;
+
+       memset(&params, 0, sizeof(params));
+
+       if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+               return -EINVAL;
+
+       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_IDX])
+               key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+       params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (key_idx > 3)
+               return -EINVAL;
+
+       /*
+        * Disallow pairwise keys with non-zero index unless it's WEP
+        * (because current deployments use pairwise WEP keys with
+        * non-zero indizes but 802.11i clearly specifies to use zero)
+        */
+       if (mac_addr && key_idx &&
+           params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+           params.cipher != WLAN_CIPHER_SUITE_WEP104)
+               return -EINVAL;
+
+       /* TODO: add definitions for the lengths to linux/ieee80211.h */
+       switch (params.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               if (params.key_len != 5)
+                       return -EINVAL;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (params.key_len != 32)
+                       return -EINVAL;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (params.key_len != 16)
+                       return -EINVAL;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               if (params.key_len != 13)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->add_key) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       u8 key_idx = 0;
+       u8 *mac_addr = NULL;
+
+       if (info->attrs[NL80211_ATTR_KEY_IDX])
+               key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+       if (key_idx > 3)
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->del_key) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+        int (*call)(struct wiphy *wiphy, struct net_device *dev,
+                   struct beacon_parameters *info);
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       struct beacon_parameters params;
+       int haveinfo = 0;
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       switch (info->genlhdr->cmd) {
+       case NL80211_CMD_NEW_BEACON:
+               /* these are required for NEW_BEACON */
+               if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+                   !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+                   !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               call = drv->ops->add_beacon;
+               break;
+       case NL80211_CMD_SET_BEACON:
+               call = drv->ops->set_beacon;
+               break;
+       default:
+               WARN_ON(1);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!call) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       memset(&params, 0, sizeof(params));
+
+       if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+               params.interval =
+                   nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+               haveinfo = 1;
+       }
+
+       if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
+               params.dtim_period =
+                   nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+               haveinfo = 1;
+       }
+
+       if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+               params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+               params.head_len =
+                   nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+               haveinfo = 1;
+       }
+
+       if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
+               params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+               params.tail_len =
+                   nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+               haveinfo = 1;
+       }
+
+       if (!haveinfo) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = call(&drv->wiphy, dev, &params);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->del_beacon) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->del_beacon(&drv->wiphy, dev);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
+       [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
+       [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
+       [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+};
+
+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+{
+       struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+       int flag;
+
+       *staflags = 0;
+
+       if (!nla)
+               return 0;
+
+       if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
+                            nla, sta_flags_policy))
+               return -EINVAL;
+
+       *staflags = STATION_FLAG_CHANGED;
+
+       for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
+               if (flags[flag])
+                       *staflags |= (1<<flag);
+
+       return 0;
+}
+
+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+                               int flags, struct net_device *dev,
+                               u8 *mac_addr, struct station_stats *stats)
+{
+       void *hdr;
+       struct nlattr *statsattr;
+
+       hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+       if (!hdr)
+               return -1;
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+       statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
+       if (!statsattr)
+               goto nla_put_failure;
+       if (stats->filled & STATION_STAT_INACTIVE_TIME)
+               NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
+                           stats->inactive_time);
+       if (stats->filled & STATION_STAT_RX_BYTES)
+               NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
+                           stats->rx_bytes);
+       if (stats->filled & STATION_STAT_TX_BYTES)
+               NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
+                           stats->tx_bytes);
+
+       nla_nest_end(msg, statsattr);
+
+       return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+       return genlmsg_cancel(msg, hdr);
+}
+
+
+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       struct station_stats stats;
+       struct sk_buff *msg;
+       u8 *mac_addr = NULL;
+
+       memset(&stats, 0, sizeof(stats));
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->get_station) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+       rtnl_unlock();
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               goto out;
+
+       if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
+                                dev, mac_addr, &stats) < 0)
+               goto out_free;
+
+       err = genlmsg_unicast(msg, info->snd_pid);
+       goto out;
+
+ out_free:
+       nlmsg_free(msg);
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+/*
+ * Get vlan interface making sure it is on the right wiphy.
+ */
+static int get_vlan(struct nlattr *vlanattr,
+                   struct cfg80211_registered_device *rdev,
+                   struct net_device **vlan)
+{
+       *vlan = NULL;
+
+       if (vlanattr) {
+               *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
+               if (!*vlan)
+                       return -ENODEV;
+               if (!(*vlan)->ieee80211_ptr)
+                       return -EINVAL;
+               if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       struct station_parameters params;
+       u8 *mac_addr = NULL;
+
+       memset(&params, 0, sizeof(params));
+
+       params.listen_interval = -1;
+
+       if (info->attrs[NL80211_ATTR_STA_AID])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
+               params.supported_rates =
+                       nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+               params.supported_rates_len =
+                       nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+       }
+
+       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+               params.listen_interval =
+                   nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+
+       if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+                               &params.station_flags))
+               return -EINVAL;
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+       if (err)
+               goto out;
+
+       if (!drv->ops->change_station) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+       rtnl_unlock();
+
+ out:
+       if (params.vlan)
+               dev_put(params.vlan);
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       struct station_parameters params;
+       u8 *mac_addr = NULL;
+
+       memset(&params, 0, sizeof(params));
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_STA_AID])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
+               return -EINVAL;
+
+       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       params.supported_rates =
+               nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+       params.supported_rates_len =
+               nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+       params.listen_interval =
+               nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+       params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+
+       if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+                               &params.station_flags))
+               return -EINVAL;
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+       if (err)
+               goto out;
+
+       if (!drv->ops->add_station) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+       rtnl_unlock();
+
+ out:
+       if (params.vlan)
+               dev_put(params.vlan);
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *drv;
+       int err;
+       struct net_device *dev;
+       u8 *mac_addr = NULL;
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       if (err)
+               return err;
+
+       if (!drv->ops->del_station) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rtnl_lock();
+       err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+       rtnl_unlock();
+
+ out:
+       cfg80211_put_dev(drv);
+       dev_put(dev);
+       return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
@@ -374,6 +1158,73 @@ static struct genl_ops nl80211_ops[] = {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
+       {
+               .cmd = NL80211_CMD_GET_KEY,
+               .doit = nl80211_get_key,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_SET_KEY,
+               .doit = nl80211_set_key,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_NEW_KEY,
+               .doit = nl80211_new_key,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_DEL_KEY,
+               .doit = nl80211_del_key,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_SET_BEACON,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .doit = nl80211_addset_beacon,
+       },
+       {
+               .cmd = NL80211_CMD_NEW_BEACON,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .doit = nl80211_addset_beacon,
+       },
+       {
+               .cmd = NL80211_CMD_DEL_BEACON,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .doit = nl80211_del_beacon,
+       },
+       {
+               .cmd = NL80211_CMD_GET_STATION,
+               .doit = nl80211_get_station,
+               /* TODO: implement dumpit */
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_SET_STATION,
+               .doit = nl80211_set_station,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_NEW_STATION,
+               .doit = nl80211_new_station,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_DEL_STATION,
+               .doit = nl80211_del_station,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
 };
 
 /* multicast groups */
diff --git a/package/mac80211/src/net/wireless/reg.c b/package/mac80211/src/net/wireless/reg.c
new file mode 100644 (file)
index 0000000..2b63c96
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * 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.
+ */
+
+/*
+ * This regulatory domain control implementation is highly incomplete, it
+ * only exists for the purpose of not regressing mac80211.
+ *
+ * For now, drivers can restrict the set of allowed channels by either
+ * not registering those channels or setting the IEEE80211_CHAN_DISABLED
+ * flag; that flag will only be *set* by this code, never *cleared.
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table and finally
+ * registering those channels in the wiphy structure.
+ *
+ * Alternatively, drivers that trust the regulatory domain control here
+ * will register a complete set of capabilities and the control code
+ * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ */
+#include <linux/kernel.h>
+#include <net/wireless.h>
+#include "core.h"
+
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+struct ieee80211_channel_range {
+       short start_freq;
+       short end_freq;
+       int max_power;
+       int max_antenna_gain;
+       u32 flags;
+};
+
+struct ieee80211_regdomain {
+       const char *code;
+       const struct ieee80211_channel_range *ranges;
+       int n_ranges;
+};
+
+#define RANGE_PWR(_start, _end, _pwr, _ag, _flags)     \
+       { _start, _end, _pwr, _ag, _flags }
+
+
+/*
+ * Ideally, in the future, these definitions will be loaded from a
+ * userspace table via some daemon.
+ */
+static const struct ieee80211_channel_range ieee80211_US_channels[] = {
+       /* IEEE 802.11b/g, channels 1..11 */
+       RANGE_PWR(2412, 2462, 27, 6, 0),
+       /* IEEE 802.11a, channels 52..64 */
+       RANGE_PWR(5260, 5320, 23, 6, 0),
+       /* IEEE 802.11a, channels 149..165, outdoor */
+       RANGE_PWR(5745, 5825, 30, 6, 0),
+};
+
+static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
+       /* IEEE 802.11b/g, channels 1..14 */
+       RANGE_PWR(2412, 2484, 20, 6, 0),
+       /* IEEE 802.11a, channels 34..48 */
+       RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+       /* IEEE 802.11a, channels 52..64 */
+       RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
+                                    IEEE80211_CHAN_RADAR),
+};
+
+#define REGDOM(_code)                                                  \
+       {                                                               \
+               .code = __stringify(_code),                             \
+               .ranges = ieee80211_ ##_code## _channels,               \
+               .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \
+       }
+
+static const struct ieee80211_regdomain ieee80211_regdoms[] = {
+       REGDOM(US),
+       REGDOM(JP),
+};
+
+
+static const struct ieee80211_regdomain *get_regdom(void)
+{
+       static const struct ieee80211_channel_range
+       ieee80211_world_channels[] = {
+               /* IEEE 802.11b/g, channels 1..11 */
+               RANGE_PWR(2412, 2462, 27, 6, 0),
+       };
+       static const struct ieee80211_regdomain regdom_world = REGDOM(world);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
+               if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
+                       return &ieee80211_regdoms[i];
+
+       return &regdom_world;
+}
+
+
+static void handle_channel(struct ieee80211_channel *chan,
+                          const struct ieee80211_regdomain *rd)
+{
+       int i;
+       u32 flags = chan->orig_flags;
+       const struct ieee80211_channel_range *rg = NULL;
+
+       for (i = 0; i < rd->n_ranges; i++) {
+               if (rd->ranges[i].start_freq <= chan->center_freq &&
+                   chan->center_freq <= rd->ranges[i].end_freq) {
+                       rg = &rd->ranges[i];
+                       break;
+               }
+       }
+
+       if (!rg) {
+               /* not found */
+               flags |= IEEE80211_CHAN_DISABLED;
+               chan->flags = flags;
+               return;
+       }
+
+       chan->flags = flags;
+       chan->max_antenna_gain = min(chan->orig_mag,
+                                        rg->max_antenna_gain);
+       chan->max_power = min(chan->orig_mpwr, rg->max_power);
+}
+
+static void handle_band(struct ieee80211_supported_band *sband,
+                       const struct ieee80211_regdomain *rd)
+{
+       int i;
+
+       for (i = 0; i < sband->n_channels; i++)
+               handle_channel(&sband->channels[i], rd);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy)
+{
+       enum ieee80211_band band;
+       const struct ieee80211_regdomain *rd = get_regdom();
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+               if (wiphy->bands[band])
+                       handle_band(wiphy->bands[band], rd);
+}
index 2d5d2255a27cd54bb12c1a21724680a5cdba617d..29f820e182511fcf8a70bf672e32887404f9cb10 100644 (file)
@@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int wiphy_uevent(struct device *dev, char **envp,
-                       int num_envp, char *buf, int size)
+static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        /* TODO, we probably need stuff here */
        return 0;
diff --git a/package/mac80211/src/net/wireless/util.c b/package/mac80211/src/net/wireless/util.c
new file mode 100644 (file)
index 0000000..77336c2
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Wireless utility functions
+ *
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/wireless.h>
+#include <asm/bitops.h>
+#include "core.h"
+
+int ieee80211_channel_to_frequency(int chan)
+{
+       if (chan < 14)
+               return 2407 + chan * 5;
+
+       if (chan == 14)
+               return 2484;
+
+       /* FIXME: 802.11j 17.3.8.3.2 */
+       return (chan + 1000) * 5;
+}
+EXPORT_SYMBOL(ieee80211_channel_to_frequency);
+
+int ieee80211_frequency_to_channel(int freq)
+{
+       if (freq == 2484)
+               return 14;
+
+       if (freq < 2484)
+               return (freq - 2407) / 5;
+
+       /* FIXME: 802.11j 17.3.8.3.2 */
+       return freq/5 - 1000;
+}
+EXPORT_SYMBOL(ieee80211_frequency_to_channel);
+
+static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
+                                    enum ieee80211_band band)
+{
+       int i, want;
+
+       switch (band) {
+       case IEEE80211_BAND_5GHZ:
+               want = 3;
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if (sband->bitrates[i].bitrate == 60 ||
+                           sband->bitrates[i].bitrate == 120 ||
+                           sband->bitrates[i].bitrate == 240) {
+                               sband->bitrates[i].flags |=
+                                       IEEE80211_RATE_MANDATORY_A;
+                               want--;
+                       }
+               }
+               WARN_ON(want);
+               break;
+       case IEEE80211_BAND_2GHZ:
+               want = 7;
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if (sband->bitrates[i].bitrate == 10) {
+                               sband->bitrates[i].flags |=
+                                       IEEE80211_RATE_MANDATORY_B |
+                                       IEEE80211_RATE_MANDATORY_G;
+                               want--;
+                       }
+
+                       if (sband->bitrates[i].bitrate == 20 ||
+                           sband->bitrates[i].bitrate == 55 ||
+                           sband->bitrates[i].bitrate == 110 ||
+                           sband->bitrates[i].bitrate == 60 ||
+                           sband->bitrates[i].bitrate == 120 ||
+                           sband->bitrates[i].bitrate == 240) {
+                               sband->bitrates[i].flags |=
+                                       IEEE80211_RATE_MANDATORY_G;
+                               want--;
+                       }
+
+                       if (sband->bitrates[i].bitrate != 10 &&
+                           sband->bitrates[i].bitrate != 20 &&
+                           sband->bitrates[i].bitrate != 55 &&
+                           sband->bitrates[i].bitrate != 110)
+                               sband->bitrates[i].flags |=
+                                       IEEE80211_RATE_ERP_G;
+               }
+               WARN_ON(want != 0 && want != 3 && want != 6);
+               break;
+       case IEEE80211_NUM_BANDS:
+               WARN_ON(1);
+               break;
+       }
+}
+
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
+{
+       enum ieee80211_band band;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+               if (wiphy->bands[band])
+                       set_mandatory_flags_band(wiphy->bands[band], band);
+}
diff --git a/package/mac80211/src/net/wireless/wext.c b/package/mac80211/src/net/wireless/wext.c
new file mode 100644 (file)
index 0000000..a2d496f
--- /dev/null
@@ -0,0 +1,1522 @@
+/*
+ * 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 <net/net_namespace.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 */
+};
+
+
+/************************ 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)
+{
+       struct seq_file *seq;
+       int res;
+       res = seq_open(file, &wireless_seq_ops);
+       if (!res) {
+               seq = file->private_data;
+               seq->private = get_proc_net(inode);
+               if (!seq->private) {
+                       seq_release(inode, file);
+                       res = -ENXIO;
+               }
+       }
+       return res;
+}
+
+static int wireless_seq_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+       struct net *net = seq->private;
+       put_net(net);
+       return seq_release(inode, file);
+}
+
+static const struct file_operations wireless_seq_fops = {
+       .owner   = THIS_MODULE,
+       .open    = wireless_seq_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = wireless_seq_release,
+};
+
+int wext_proc_init(struct net *net)
+{
+       /* Create /proc/net/wireless entry */
+       if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
+               return -ENOMEM;
+
+       return 0;
+}
+
+void wext_proc_exit(struct net *net)
+{
+       proc_net_remove(net, "wireless");
+}
+#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 net *net, 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(net, 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 net *net, 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(net, ifr->ifr_name);
+       rtnl_lock();
+       ret = wireless_process_ioctl(net, ifr, cmd);
+       rtnl_unlock();
+       if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
+               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;
+
+       nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0);
+       if (nlh == NULL)
+               return -EMSGSIZE;
+
+       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 */
+       NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
+
+       return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * 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 err;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
+       if (err < 0) {
+               WARN_ON(err == -EMSGSIZE);
+               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);