summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormb <mb@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-02-15 22:47:47 +0000
committermb <mb@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-02-15 22:47:47 +0000
commit8b781781653ed21133e9f240e350951c24e94fb2 (patch)
tree23c839cece6d908d1b71914c4ebf9576dfc8d07e
parent8edc7d7a47705374d16bc2417ee4fdf2bff17cce (diff)
Upgrade b43 and mac80211.
This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211. Will do that in a seperate patch. git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10466 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--package/b43/Makefile9
-rw-r--r--package/b43/src/Kconfig68
-rw-r--r--package/b43/src/Makefile12
-rw-r--r--package/b43/src/b43.h158
-rw-r--r--package/b43/src/debugfs.c11
-rw-r--r--package/b43/src/dma.c316
-rw-r--r--package/b43/src/dma.h70
-rw-r--r--package/b43/src/leds.c14
-rw-r--r--package/b43/src/lo.c72
-rw-r--r--package/b43/src/main.c1358
-rw-r--r--package/b43/src/main.h25
-rw-r--r--package/b43/src/nphy.c489
-rw-r--r--package/b43/src/nphy.h932
-rw-r--r--package/b43/src/pcmcia.c52
-rw-r--r--package/b43/src/phy.c1012
-rw-r--r--package/b43/src/phy.h103
-rw-r--r--package/b43/src/pio.c652
-rw-r--r--package/b43/src/pio.h153
-rw-r--r--package/b43/src/rfkill.c147
-rw-r--r--package/b43/src/rfkill.h14
-rw-r--r--package/b43/src/sysfs.c89
-rw-r--r--package/b43/src/tables.c112
-rw-r--r--package/b43/src/tables.h12
-rw-r--r--package/b43/src/tables_nphy.c2476
-rw-r--r--package/b43/src/tables_nphy.h159
-rw-r--r--package/b43/src/wa.c674
-rw-r--r--package/b43/src/wa.h7
-rw-r--r--package/b43/src/xmit.c302
-rw-r--r--package/b43/src/xmit.h277
-rw-r--r--package/hostapd/files/default.config2
-rw-r--r--package/hostapd/files/mini.config2
-rw-r--r--package/mac80211/Makefile9
-rw-r--r--package/mac80211/patches/000-mac80211_update.patch933
-rw-r--r--package/mac80211/patches/001-port-to-2.6.23.patch231
-rw-r--r--package/mac80211/patches/008-add-hostapd-ioctl-header.patch110
-rw-r--r--package/mac80211/patches/009-add-old-ioctl-skeleton.patch187
-rw-r--r--package/mac80211/patches/010-add-mgmt-iface.patch688
-rw-r--r--package/mac80211/patches/011-allow-ap-vlan-modes.patch37
-rw-r--r--package/mac80211/patches/012-mac80211-allow-wds.patch22
-rw-r--r--package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch26
-rw-r--r--package/mac80211/patches/014-prism2-ioctl-8021x.patch26
-rw-r--r--package/mac80211/patches/015-hostapd-ioctl-hw-features.patch122
-rw-r--r--package/mac80211/patches/016-prism2-ioctl-eapol.patch26
-rw-r--r--package/mac80211/patches/017-nl80211-add-key-mgmt.patch470
-rw-r--r--package/mac80211/patches/018-mac80211-cfg80211-keys.patch120
-rw-r--r--package/mac80211/patches/019-mac80211-key-seq-nl80211.patch161
-rw-r--r--package/mac80211/patches/020-nl80211-beacon-parameters.patch279
-rw-r--r--package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch484
-rw-r--r--package/mac80211/patches/022-nl80211-sta.patch464
-rw-r--r--package/mac80211/patches/023-mac80211-implement-sta.patch224
-rw-r--r--package/mac80211/patches/024-nl80211-get-sta.patch208
-rw-r--r--package/mac80211/patches/025-mac80211-get-sta.patch51
-rw-r--r--package/mac80211/src/include/linux/ieee80211.h161
-rw-r--r--package/mac80211/src/include/linux/nl80211.h255
-rw-r--r--package/mac80211/src/include/net/cfg80211.h191
-rw-r--r--package/mac80211/src/include/net/mac80211.h548
-rw-r--r--package/mac80211/src/include/net/wireless.h307
-rw-r--r--package/mac80211/src/net/mac80211/Kconfig100
-rw-r--r--package/mac80211/src/net/mac80211/Makefile37
-rw-r--r--package/mac80211/src/net/mac80211/aes_ccm.c6
-rw-r--r--package/mac80211/src/net/mac80211/cfg.c577
-rw-r--r--package/mac80211/src/net/mac80211/debugfs.c47
-rw-r--r--package/mac80211/src/net/mac80211/debugfs_key.c3
-rw-r--r--package/mac80211/src/net/mac80211/debugfs_netdev.c54
-rw-r--r--package/mac80211/src/net/mac80211/debugfs_sta.c141
-rw-r--r--package/mac80211/src/net/mac80211/event.c5
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211.c815
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_common.h91
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_i.h213
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_iface.c21
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_ioctl.c265
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_led.c35
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_led.h6
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_rate.c83
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_rate.h109
-rw-r--r--package/mac80211/src/net/mac80211/ieee80211_sta.c1583
-rw-r--r--package/mac80211/src/net/mac80211/key.c16
-rw-r--r--package/mac80211/src/net/mac80211/rc80211_pid.h285
-rw-r--r--package/mac80211/src/net/mac80211/rc80211_pid_algo.c550
-rw-r--r--package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c223
-rw-r--r--package/mac80211/src/net/mac80211/rc80211_simple.c154
-rw-r--r--package/mac80211/src/net/mac80211/regdomain.c152
-rw-r--r--package/mac80211/src/net/mac80211/rx.c1250
-rw-r--r--package/mac80211/src/net/mac80211/sta_info.c99
-rw-r--r--package/mac80211/src/net/mac80211/sta_info.h135
-rw-r--r--package/mac80211/src/net/mac80211/tkip.c10
-rw-r--r--package/mac80211/src/net/mac80211/tx.c671
-rw-r--r--package/mac80211/src/net/mac80211/util.c269
-rw-r--r--package/mac80211/src/net/mac80211/wep.c41
-rw-r--r--package/mac80211/src/net/mac80211/wep.h4
-rw-r--r--package/mac80211/src/net/mac80211/wme.c144
-rw-r--r--package/mac80211/src/net/mac80211/wme.h23
-rw-r--r--package/mac80211/src/net/mac80211/wpa.c115
-rw-r--r--package/mac80211/src/net/mac80211/wpa.h12
-rw-r--r--package/mac80211/src/net/wireless/Kconfig12
-rw-r--r--package/mac80211/src/net/wireless/Makefile3
-rw-r--r--package/mac80211/src/net/wireless/core.c48
-rw-r--r--package/mac80211/src/net/wireless/core.h3
-rw-r--r--package/mac80211/src/net/wireless/nl80211.c857
-rw-r--r--package/mac80211/src/net/wireless/reg.c153
-rw-r--r--package/mac80211/src/net/wireless/sysfs.c3
-rw-r--r--package/mac80211/src/net/wireless/util.c98
-rw-r--r--package/mac80211/src/net/wireless/wext.c1522
103 files changed, 16995 insertions, 10167 deletions
diff --git a/package/b43/Makefile b/package/b43/Makefile
index c4cc91f5cf..e47d5165eb 100644
--- a/package/b43/Makefile
+++ b/package/b43/Makefile
@@ -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
diff --git a/package/b43/src/Kconfig b/package/b43/src/Kconfig
index e3c573e56b..1a2141dabd 100644
--- a/package/b43/src/Kconfig
+++ b/package/b43/src/Kconfig
@@ -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
diff --git a/package/b43/src/Makefile b/package/b43/src/Makefile
index 485e59e2df..ac1329dba0 100644
--- a/package/b43/src/Makefile
+++ b/package/b43/src/Makefile
@@ -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
diff --git a/package/b43/src/b43.h b/package/b43/src/b43.h
index a28ad230d6..0dc1aaf46b 100644
--- a/package/b43/src/b43.h
+++ b/package/b43/src/b43.h
@@ -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
@@ -65,11 +68,6 @@
#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);
diff --git a/package/b43/src/debugfs.c b/package/b43/src/debugfs.c
index 734e70e1a0..e38ed0fe72 100644
--- a/package/b43/src/debugfs.c
+++ b/package/b43/src/debugfs.c
@@ -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);
diff --git a/package/b43/src/dma.c b/package/b43/src/dma.c
index 5e8f8ac0f1..3dfb28a34b 100644
--- a/package/b43/src/dma.c
+++ b/package/b43/src/dma.c
@@ -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);
diff --git a/package/b43/src/dma.h b/package/b43/src/dma.h
index 3eed185be7..c0d6b69e65 100644
--- a/package/b43/src/dma.h
+++ b/package/b43/src/dma.h
@@ -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_ */
diff --git a/package/b43/src/leds.c b/package/b43/src/leds.c
index 19e588582c..4b590d8c65 100644
--- a/package/b43/src/leds.c
+++ b/package/b43/src/leds.c
@@ -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);
}
diff --git a/package/b43/src/lo.c b/package/b43/src/lo.c
index b14a1753a0..d890f366a2 100644
--- a/package/b43/src/lo.c
+++ b/package/b43/src/lo.c
@@ -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);
diff --git a/package/b43/src/main.c b/package/b43/src/main.c
index 9f8175c25a..afb109447a 100644
--- a/package/b43/src/main.c
+++ b/package/b43/src/main.c
@@ -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();
}
diff --git a/package/b43/src/main.h b/package/b43/src/main.h
index 284d17da17..2d52d9de93 100644
--- a/package/b43/src/main.h
+++ b/package/b43/src/main.h
@@ -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>
@@ -39,11 +39,11 @@
#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
index 0000000000..705131ef4b
--- /dev/null
+++ b/package/b43/src/nphy.c
@@ -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
index 0000000000..5d95118b81
--- /dev/null
+++ b/package/b43/src/nphy.h
@@ -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_ */
diff --git a/package/b43/src/pcmcia.c b/package/b43/src/pcmcia.c
index b242a9a90d..b79a6bd539 100644
--- a/package/b43/src/pcmcia.c
+++ b/package/b43/src/pcmcia.c
@@ -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)
diff --git a/package/b43/src/phy.c b/package/b43/src/phy.c
index 3d4ed647c3..71507b260b 100644
--- a/package/b43/src/phy.c
+++ b/package/b43/src/phy.c
@@ -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>
@@ -31,9 +31,12 @@
#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;
}
diff --git a/package/b43/src/phy.h b/package/b43/src/phy.h
index c64d74504f..6d165d8221 100644
--- a/package/b43/src/phy.h
+++ b/package/b43/src/phy.h
@@ -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
index 67752a28eb..0000000000
--- a/package/b43/src/pio.c
+++ /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
index 3488f2447b..0000000000
--- a/package/b43/src/pio.h
+++ /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_ */
diff --git a/package/b43/src/rfkill.c b/package/b43/src/rfkill.c
index 800e0a61a7..11f53cb113 100644
--- a/package/b43/src/rfkill.c
+++ b/package/b43/src/rfkill.c
@@ -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;
}
diff --git a/package/b43/src/rfkill.h b/package/b43/src/rfkill.h
index 29544e8c9e..adacf936d8 100644
--- a/package/b43/src/rfkill.h
+++ b/package/b43/src/rfkill.h
@@ -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)
{
}
diff --git a/package/b43/src/sysfs.c b/package/b43/src/sysfs.c
index f4faff6a7d..275095b8cb 100644
--- a/package/b43/src/sysfs.c
+++ b/package/b43/src/sysfs.c
@@ -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);
}
diff --git a/package/b43/src/tables.c b/package/b43/src/tables.c
index 15a87183a5..3f5ea06bf1 100644
--- a/package/b43/src/tables.c
+++ b/package/b43/src/tables.c
@@ -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));
}
diff --git a/package/b43/src/tables.h b/package/b43/src/tables.h
index 64635d7b51..80e73c7cba 100644
--- a/package/b43/src/tables.h
+++ b/package/b43/src/tables.h
@@ -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
index 0000000000..2aa5755178
--- /dev/null
+++ b/package/b43/src/tables_nphy.c
@@ -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
index 0000000000..4d498b053e
--- /dev/null
+++ b/package/b43/src/tables_nphy.h
@@ -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
index 0000000000..e632125cb7
--- /dev/null
+++ b/package/b43/src/wa.c
@@ -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
index 0000000000..e163c5e56e
--- /dev/null
+++ b/package/b43/src/wa.h
@@ -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_ */
diff --git a/package/b43/src/xmit.c b/package/b43/src/xmit.c
index 0bd6f8a348..4014b6c827 100644
--- a/package/b43/src/xmit.c
+++ b/package/b43/src/xmit.c
@@ -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>
@@ -30,48 +30,50 @@
#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
diff --git a/package/b43/src/xmit.h b/package/b43/src/xmit.h
index 03bddd2516..4176503955 100644
--- a/package/b43/src/xmit.h
+++ b/package/b43/src/xmit.h
@@ -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);
diff --git a/package/hostapd/files/default.config b/package/hostapd/files/default.config
index 700217dada..f383e116cd 100644
--- a/package/hostapd/files/default.config
+++ b/package/hostapd/files/default.config
@@ -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
diff --git a/package/hostapd/files/mini.config b/package/hostapd/files/mini.config
index a2f3f62bba..d1ab057ccc 100644
--- a/package/hostapd/files/mini.config
+++ b/package/hostapd/files/mini.config
@@ -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
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile
index 723ba77be5..9d8320e180 100644
--- a/package/mac80211/Makefile
+++ b/package/mac80211/Makefile
@@ -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
index 7a1a1e271b..0000000000
--- a/package/mac80211/patches/000-mac80211_update.patch
+++ /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
index 0000000000..2e88d405e3
--- /dev/null
+++ b/package/mac80211/patches/001-port-to-2.6.23.patch
@@ -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
index acea0ce969..0000000000
--- a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch
+++ /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
index fb9f25f62a..0000000000
--- a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch
+++ /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
index eae5ff6d5e..0000000000
--- a/package/mac80211/patches/010-add-mgmt-iface.patch
+++ /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
index d0edfe835c..0000000000
--- a/package/mac80211/patches/011-allow-ap-vlan-modes.patch
+++ /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
index d5c57cd019..0000000000
--- a/package/mac80211/patches/012-mac80211-allow-wds.patch
+++ /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
index d418ad3497..0000000000
--- a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch
+++ /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
index 5feb01ea32..0000000000
--- a/package/mac80211/patches/014-prism2-ioctl-8021x.patch
+++ /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
index d6e5dfd073..0000000000
--- a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch
+++ /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
index 5ce57587ab..0000000000
--- a/package/mac80211/patches/016-prism2-ioctl-eapol.patch
+++ /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
index f5b1d45c15..0000000000
--- a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch
+++ /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
index 0c98623a2d..0000000000
--- a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch
+++ /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
index 5d0020b7fe..0000000000
--- a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch
+++ /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
index 51836f332f..0000000000
--- a/package/mac80211/patches/020-nl80211-beacon-parameters.patch
+++ /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
index 702c68f98f..0000000000
--- a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch
+++ /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
index 4d08721f82..0000000000
--- a/package/mac80211/patches/022-nl80211-sta.patch
+++ /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
index 095067676c..0000000000
--- a/package/mac80211/patches/023-mac80211-implement-sta.patch
+++ /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
index 198ad1876b..0000000000
--- a/package/mac80211/patches/024-nl80211-get-sta.patch
+++ /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
index 868ca86fa3..0000000000
--- a/package/mac80211/patches/025-mac80211-get-sta.patch
+++ /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,
- };
diff --git a/package/mac80211/src/include/linux/ieee80211.h b/package/mac80211/src/include/linux/ieee80211.h
index 30621c2715..f577c8f1c6 100644
--- a/package/mac80211/src/include/linux/ieee80211.h
+++ b/package/mac80211/src/include/linux/ieee80211.h
@@ -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
@@ -81,18 +83,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
@@ -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
diff --git a/package/mac80211/src/include/linux/nl80211.h b/package/mac80211/src/include/linux/nl80211.h
index a5dd030d50..a9f0b93324 100644
--- a/package/mac80211/src/include/linux/nl80211.h
+++ b/package/mac80211/src/include/linux/nl80211.h
@@ -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
@@ -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
@@ -37,6 +49,35 @@
* 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 */
diff --git a/package/mac80211/src/include/net/cfg80211.h b/package/mac80211/src/include/net/cfg80211.h
index d30960e175..ab4caf6395 100644
--- a/package/mac80211/src/include/net/cfg80211.h
+++ b/package/mac80211/src/include/net/cfg80211.h
@@ -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 */
diff --git a/package/mac80211/src/include/net/mac80211.h b/package/mac80211/src/include/net/mac80211.h
index 2b1bffbf5e..460da54a00 100644
--- a/package/mac80211/src/include/net/mac80211.h
+++ b/package/mac80211/src/include/net/mac80211.h
@@ -69,95 +69,20 @@
* 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;
};
/**
@@ -480,13 +442,27 @@ enum ieee80211_if_types {
};
/**
+ * 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
index 0000000000..c7f805ee55
--- /dev/null
+++ b/package/mac80211/src/include/net/wireless.h
@@ -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 */
diff --git a/package/mac80211/src/net/mac80211/Kconfig b/package/mac80211/src/net/mac80211/Kconfig
index 6fffb3845a..45c7c0c387 100644
--- a/package/mac80211/src/net/mac80211/Kconfig
+++ b/package/mac80211/src/net/mac80211/Kconfig
@@ -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
diff --git a/package/mac80211/src/net/mac80211/Makefile b/package/mac80211/src/net/mac80211/Makefile
index 219cd9f934..9d7a19581a 100644
--- a/package/mac80211/src/net/mac80211/Makefile
+++ b/package/mac80211/src/net/mac80211/Makefile
@@ -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)
diff --git a/package/mac80211/src/net/mac80211/aes_ccm.c b/package/mac80211/src/net/mac80211/aes_ccm.c
index e55569bee7..e62fe55944 100644
--- a/package/mac80211/src/net/mac80211/aes_ccm.c
+++ b/package/mac80211/src/net/mac80211/aes_ccm.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/cfg.c b/package/mac80211/src/net/mac80211/cfg.c
index cd78b3f29c..a083cc7885 100644
--- a/package/mac80211/src/net/mac80211/cfg.c
+++ b/package/mac80211/src/net/mac80211/cfg.c
@@ -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,
};
diff --git a/package/mac80211/src/net/mac80211/debugfs.c b/package/mac80211/src/net/mac80211/debugfs.c
index 60514b2c97..4736c64937 100644
--- a/package/mac80211/src/net/mac80211/debugfs.c
+++ b/package/mac80211/src/net/mac80211/debugfs.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/debugfs_key.c b/package/mac80211/src/net/mac80211/debugfs_key.c
index 8e4a1bcd16..c881524c87 100644
--- a/package/mac80211/src/net/mac80211/debugfs_key.c
+++ b/package/mac80211/src/net/mac80211/debugfs_key.c
@@ -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);
}
diff --git a/package/mac80211/src/net/mac80211/debugfs_netdev.c b/package/mac80211/src/net/mac80211/debugfs_netdev.c
index 2b5e7615e5..29f7b98ba1 100644
--- a/package/mac80211/src/net/mac80211/debugfs_netdev.c
+++ b/package/mac80211/src/net/mac80211/debugfs_netdev.c
@@ -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;
}
diff --git a/package/mac80211/src/net/mac80211/debugfs_sta.c b/package/mac80211/src/net/mac80211/debugfs_sta.c
index 4ea0ea7ea0..ac61353ae7 100644
--- a/package/mac80211/src/net/mac80211/debugfs_sta.c
+++ b/package/mac80211/src/net/mac80211/debugfs_sta.c
@@ -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;
diff --git a/package/mac80211/src/net/mac80211/event.c b/package/mac80211/src/net/mac80211/event.c
index 68a526cb76..2280f40b45 100644
--- a/package/mac80211/src/net/mac80211/event.c
+++ b/package/mac80211/src/net/mac80211/event.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/ieee80211.c b/package/mac80211/src/net/mac80211/ieee80211.c
index 64fa7204b4..1a0171d2f1 100644
--- a/package/mac80211/src/net/mac80211/ieee80211.c
+++ b/package/mac80211/src/net/mac80211/ieee80211.c
@@ -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
index c15295d43d..0000000000
--- a/package/mac80211/src/net/mac80211/ieee80211_common.h
+++ /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 */
diff --git a/package/mac80211/src/net/mac80211/ieee80211_i.h b/package/mac80211/src/net/mac80211/ieee80211_i.h
index d34a9deca6..1b4a449703 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_i.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_i.h
@@ -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,
diff --git a/package/mac80211/src/net/mac80211/ieee80211_iface.c b/package/mac80211/src/net/mac80211/ieee80211_iface.c
index 43e505d294..f66f1ddc3f 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_iface.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_iface.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
index f95d488726..54ad07aafe 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
@@ -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;
diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.c b/package/mac80211/src/net/mac80211/ieee80211_led.c
index 4cf89af9d1..f401484ab6 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_led.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_led.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.h b/package/mac80211/src/net/mac80211/ieee80211_led.h
index 0feb226198..77b1e1ba60 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_led.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_led.h
@@ -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)
{
}
diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.c b/package/mac80211/src/net/mac80211/ieee80211_rate.c
index 93abb8fff1..ebe29b716b 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_rate.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_rate.c
@@ -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);
}
+
diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.h b/package/mac80211/src/net/mac80211/ieee80211_rate.h
index 7cd1ebab4f..5f9a2ca49a 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_rate.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_rate.h
@@ -18,31 +18,26 @@
#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 */
diff --git a/package/mac80211/src/net/mac80211/ieee80211_sta.c b/package/mac80211/src/net/mac80211/ieee80211_sta.c
index 7c93f29c8b..92d7450e2c 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_sta.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_sta.c
@@ -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)
@@ -58,10 +57,25 @@
#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))
diff --git a/package/mac80211/src/net/mac80211/key.c b/package/mac80211/src/net/mac80211/key.c
index d9ab0871fe..ed57fb8e82 100644
--- a/package/mac80211/src/net/mac80211/key.c
+++ b/package/mac80211/src/net/mac80211/key.c
@@ -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
index 0000000000..04afc13ed8
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid.h
@@ -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
index 0000000000..da8462bbd5
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c
@@ -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
index 0000000000..88b8dc9999
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
@@ -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);
+}
diff --git a/package/mac80211/src/net/mac80211/rc80211_simple.c b/package/mac80211/src/net/mac80211/rc80211_simple.c
index ef91ce428a..c4678905a1 100644
--- a/package/mac80211/src/net/mac80211/rc80211_simple.c
+++ b/package/mac80211/src/net/mac80211/rc80211_simple.c
@@ -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"
@@ -24,19 +24,19 @@
/* 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
index f42678fa62..0000000000
--- a/package/mac80211/src/net/mac80211/regdomain.c
+++ /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;
-}
-
diff --git a/package/mac80211/src/net/mac80211/rx.c b/package/mac80211/src/net/mac80211/rx.c
index 064924cb28..943ba90829 100644
--- a/package/mac80211/src/net/mac80211/rx.c
+++ b/package/mac80211/src/net/mac80211/rx.c
@@ -24,6 +24,10 @@
#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);
diff --git a/package/mac80211/src/net/mac80211/sta_info.c b/package/mac80211/src/net/mac80211/sta_info.c
index 4ed1b60bb1..6b53783966 100644
--- a/package/mac80211/src/net/mac80211/sta_info.c
+++ b/package/mac80211/src/net/mac80211/sta_info.c
@@ -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;
diff --git a/package/mac80211/src/net/mac80211/sta_info.h b/package/mac80211/src/net/mac80211/sta_info.h
index 8f7ebe41c0..19f3fb4129 100644
--- a/package/mac80211/src/net/mac80211/sta_info.h
+++ b/package/mac80211/src/net/mac80211/sta_info.h
@@ -15,22 +15,110 @@
#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);
diff --git a/package/mac80211/src/net/mac80211/tkip.c b/package/mac80211/src/net/mac80211/tkip.c
index 876cbe3710..3abe194e4d 100644
--- a/package/mac80211/src/net/mac80211/tkip.c
+++ b/package/mac80211/src/net/mac80211/tkip.c
@@ -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[
diff --git a/package/mac80211/src/net/mac80211/tx.c b/package/mac80211/src/net/mac80211/tx.c
index 957ec3c830..181d97015f 100644
--- a/package/mac80211/src/net/mac80211/tx.c
+++ b/package/mac80211/src/net/mac80211/tx.c
@@ -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;
}
diff --git a/package/mac80211/src/net/mac80211/util.c b/package/mac80211/src/net/mac80211/util.c
index 27203f1b95..f64804fed0 100644
--- a/package/mac80211/src/net/mac80211/util.c
+++ b/package/mac80211/src/net/mac80211/util.c
@@ -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);
diff --git a/package/mac80211/src/net/mac80211/wep.c b/package/mac80211/src/net/mac80211/wep.c
index 6675261e95..a33ef5cfa9 100644
--- a/package/mac80211/src/net/mac80211/wep.c
+++ b/package/mac80211/src/net/mac80211/wep.c
@@ -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;
}
diff --git a/package/mac80211/src/net/mac80211/wep.h b/package/mac80211/src/net/mac80211/wep.h
index 785fbb4e0d..43aef50cd0 100644
--- a/package/mac80211/src/net/mac80211/wep.h
+++ b/package/mac80211/src/net/mac80211/wep.h
@@ -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 */
diff --git a/package/mac80211/src/net/mac80211/wme.c b/package/mac80211/src/net/mac80211/wme.c
index 5b8a157975..7bbc79371d 100644
--- a/package/mac80211/src/net/mac80211/wme.c
+++ b/package/mac80211/src/net/mac80211/wme.c
@@ -19,15 +19,19 @@
#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);
+ }
+}
diff --git a/package/mac80211/src/net/mac80211/wme.h b/package/mac80211/src/net/mac80211/wme.h
index 76c713a645..fcc6b05508 100644
--- a/package/mac80211/src/net/mac80211/wme.h
+++ b/package/mac80211/src/net/mac80211/wme.h
@@ -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;
diff --git a/package/mac80211/src/net/mac80211/wpa.c b/package/mac80211/src/net/mac80211/wpa.c
index 0b32ab64eb..b35e51c6ce 100644
--- a/package/mac80211/src/net/mac80211/wpa.c
+++ b/package/mac80211/src/net/mac80211/wpa.c
@@ -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;
}
-
diff --git a/package/mac80211/src/net/mac80211/wpa.h b/package/mac80211/src/net/mac80211/wpa.h
index 49d80cf0cd..16e4dba4aa 100644
--- a/package/mac80211/src/net/mac80211/wpa.h
+++ b/package/mac80211/src/net/mac80211/wpa.h
@@ -13,19 +13,19 @@
#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 */
diff --git a/package/mac80211/src/net/wireless/Kconfig b/package/mac80211/src/net/wireless/Kconfig
index 6291f13bba..79270903bd 100644
--- a/package/mac80211/src/net/wireless/Kconfig
+++ b/package/mac80211/src/net/wireless/Kconfig
@@ -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"
diff --git a/package/mac80211/src/net/wireless/Makefile b/package/mac80211/src/net/wireless/Makefile
index 5664c2cfd7..b9f943c45f 100644
--- a/package/mac80211/src/net/wireless/Makefile
+++ b/package/mac80211/src/net/wireless/Makefile
@@ -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
diff --git a/package/mac80211/src/net/wireless/core.c b/package/mac80211/src/net/wireless/core.c
index 35b79bee3a..80afacdae4 100644
--- a/package/mac80211/src/net/wireless/core.c
+++ b/package/mac80211/src/net/wireless/core.c
@@ -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);
diff --git a/package/mac80211/src/net/wireless/core.h b/package/mac80211/src/net/wireless/core.h
index eb0f846b40..7a02c356d6 100644
--- a/package/mac80211/src/net/wireless/core.h
+++ b/package/mac80211/src/net/wireless/core.h
@@ -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 */
diff --git a/package/mac80211/src/net/wireless/nl80211.c b/package/mac80211/src/net/wireless/nl80211.c
index 58717f3037..5b3474798b 100644
--- a/package/mac80211/src/net/wireless/nl80211.c
+++ b/package/mac80211/src/net/wireless/nl80211.c
@@ -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
index 0000000000..2b63c96dcf
--- /dev/null
+++ b/package/mac80211/src/net/wireless/reg.c
@@ -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);
+}
diff --git a/package/mac80211/src/net/wireless/sysfs.c b/package/mac80211/src/net/wireless/sysfs.c
index 2d5d2255a2..29f820e182 100644
--- a/package/mac80211/src/net/wireless/sysfs.c
+++ b/package/mac80211/src/net/wireless/sysfs.c
@@ -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
index 0000000000..77336c22fc
--- /dev/null
+++ b/package/mac80211/src/net/wireless/util.c
@@ -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
index 0000000000..a2d496f0b3
--- /dev/null
+++ b/package/mac80211/src/net/wireless/wext.c
@@ -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);