This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211.
Will do that in a seperate patch.
SVN-Revision: 10466
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
EXTRA_KCONFIG:= \
CONFIG_B43=m \
- CONFIG_B43_DMA=y \
$(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \
$(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
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
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
-# 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
#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
#define B43_MMIO_XMITSTAT_1 0x174
#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+#define B43_MMIO_TSF_CFP_REP 0x188
+#define B43_MMIO_TSF_CFP_START 0x18C
+#define B43_MMIO_TSF_CFP_MAXDUR 0x190
/* 32-bit DMA */
#define B43_MMIO_DMA32_BASE0 0x200
#define B43_MMIO_DMA64_BASE3 0x2C0
#define B43_MMIO_DMA64_BASE4 0x300
#define B43_MMIO_DMA64_BASE5 0x340
-/* PIO */
-#define B43_MMIO_PIO1_BASE 0x300
-#define B43_MMIO_PIO2_BASE 0x310
-#define B43_MMIO_PIO3_BASE 0x320
-#define B43_MMIO_PIO4_BASE 0x330
#define B43_MMIO_PHY_VER 0x3E0
#define B43_MMIO_PHY_RADIO 0x3E2
#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 */
#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 */
#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
#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
#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. */
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;
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. */
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;
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;
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. */
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;
/* 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 */
/* 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 */
/* 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;
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;
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);
#include "main.h"
#include "debugfs.h"
#include "dma.h"
-#include "pio.h"
#include "xmit.h"
__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);
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)) {
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;
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);
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
/* 32bit DMA ops. */
static
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)
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,
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];
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;
}
/* 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;
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;
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;
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 ||
}
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;
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)
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;
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;
}
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)
b43_dma_write(ring, B43_DMA64_TXRINGHI,
((ringbase >> 32) &
~SSB_DMA_TRANSLATION_MASK)
- | trans);
+ | (trans << 1));
} else {
u32 ringbase = (u32) (ring->dmabase);
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)
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);
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;
}
{
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
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;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
+ ring->type = type;
nr_slots = B43_RXRING_SLOTS;
if (for_tx)
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;
/* 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;
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,
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;
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;
* 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;
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:
{
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);
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;
}
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;
}
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;
}
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)) {
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;
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
}
}
- out_unlock:
+out_unlock:
spin_unlock_irqrestore(&ring->lock, flags);
return err;
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);
#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;
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;
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. */
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);
}
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);
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_ */
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>
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:
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) {
b43_unregister_led(&dev->led_tx);
b43_unregister_led(&dev->led_rx);
b43_unregister_led(&dev->led_assoc);
+ b43_unregister_led(&dev->led_radio);
}
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>
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);
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;
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,
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);
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,
& 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);
} 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);
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);
& 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;
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);
}
}
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);
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);
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)) {
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);
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>
#include "debugfs.h"
#include "phy.h"
#include "dma.h"
-#include "pio.h"
#include "sysfs.h"
#include "xmit.h"
#include "lo.h"
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.");
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)
#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),
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),
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);
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;
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) {
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) {
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 */
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);
}
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)
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);
* 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;
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;
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;
/* 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)
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)
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))) {
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);
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]);
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:
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;
}
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:
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 */
}
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;
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 */
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",
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;
}
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;
}
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;
}
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);
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);
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);
/* 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);
}
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 */
}
{
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)
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);
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);
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;
}
{
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)) {
}
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)
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;
}
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;
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;
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;
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:
/* 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)) !=
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) {
}
/* 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))
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)
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:
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;
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;
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
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);
}
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);
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");
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;
};
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)
if (radio_ver != 0x2050)
unsupported = 1;
break;
+ case B43_PHYTYPE_N:
+ if (radio_ver != 0x2055)
+ unsupported = 1;
+ break;
default:
B43_WARN_ON(1);
}
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;
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;
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;
#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);
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);
}
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;
}
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);
/* 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
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:
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;
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);
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;
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;
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;
}
if (err) {
if (did_init)
b43_wireless_core_exit(dev);
+ do_rfkill_exit = 1;
goto out_mutex_unlock;
}
}
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);
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.
}
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);
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.
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);
(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;
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);
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);
/* 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)
}
/* 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);
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);
.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;
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:
static void __exit b43_exit(void)
{
ssb_driver_unregister(&b43_ssb_driver);
- b43_pci_ssb_bridge_exit();
b43_pcmcia_exit();
b43_debugfs_exit();
}
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
+ Stefano Brivio <stefano.brivio@polimi.it>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline u8 b43_freq_to_channel_a(int freq)
+static inline u8 b43_freq_to_channel_5ghz(int freq)
{
return ((freq - 5000) / 5);
}
-static inline u8 b43_freq_to_channel_bg(int freq)
+static inline u8 b43_freq_to_channel_2ghz(int freq)
{
u8 channel;
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;
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)
{
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);
--- /dev/null
+/*
+
+ 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;
+}
--- /dev/null
+#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_ */
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;
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;
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;
}
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)
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
#include "b43.h"
#include "phy.h"
+#include "nphy.h"
#include "main.h"
#include "tables.h"
#include "lo.h"
+#include "wa.h"
+
static const s8 b43_tssi2dbm_b_table[] = {
0x4D, 0x4C, 0x4B, 0x4A,
}
}
-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.
{
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;
}
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,
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. */
{
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)
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);
}
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 {
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);
}
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;
(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);
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) {
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,
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)
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);
| 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.
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);
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:
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);
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);
}
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)) {
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;
}
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;
<< 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);
}
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
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);
}
{
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) {
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);
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)
{
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,
ret[j] = 1;
}
b43_radio_unlock(dev);
- b43_phy_unlock(dev, phylock_flags);
+ b43_phy_unlock(dev);
return ret[channel - 1];
}
if (phy->radio_ver != 0x2050)
return;
if (!
- (dev->dev->bus->sprom.r1.
+ (dev->dev->bus->sprom.
boardflags_lo & B43_BFL_RSSI))
return;
}
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;
}
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) {
}
} 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) {
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;
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);
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,
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,
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,
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,
}
udelay(10);
- b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
tmp1++;
tmp1 >>= 9;
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,
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,
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,
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) {
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);
}
* 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);
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);
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);
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)
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);
}
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);
}
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;
}
/*** 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 */
#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) */
#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) */
#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 */
#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 */
#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)
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,
#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);
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);
+++ /dev/null
-/*
-
- 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);
-}
+++ /dev/null
-#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_ */
#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)
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) {
b43_radio_turn_off(dev, 0);
break;
}
-
out_unlock:
mutex_unlock(&wl->mutex);
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)
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;
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;
}
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);
/* 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)
{
}
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)
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);
}
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>
};
const u16 b43_tab_noisea3[] = {
- 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+ 0x5E5E, 0x5E5E, 0x5E5E, 0x3F48,
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
};
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,
};
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,
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));
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);
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));
}
#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[];
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_ */
--- /dev/null
+/*
+
+ 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();
+}
--- /dev/null
+#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_ */
--- /dev/null
+/*
+
+ 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);
+}
--- /dev/null
+#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_ */
Transmission (TX/RX) related functions.
Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
- Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
#include "xmit.h"
#include "phy.h"
#include "dma.h"
-#include "pio.h"
-/* Extract the bitrate out of a CCK PLCP header. */
-static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+
+/* Extract the bitrate index out of a CCK PLCP header. */
+static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
- return B43_CCK_RATE_1MB;
+ return 0;
case 0x14:
- return B43_CCK_RATE_2MB;
+ return 1;
case 0x37:
- return B43_CCK_RATE_5MB;
+ return 2;
case 0x6E:
- return B43_CCK_RATE_11MB;
+ return 3;
}
B43_WARN_ON(1);
- return 0;
+ return -1;
}
-/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+/* Extract the bitrate index out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
{
+ int base = aphy ? 0 : 4;
+
switch (plcp->raw[0] & 0xF) {
case 0xB:
- return B43_OFDM_RATE_6MB;
+ return base + 0;
case 0xF:
- return B43_OFDM_RATE_9MB;
+ return base + 1;
case 0xA:
- return B43_OFDM_RATE_12MB;
+ return base + 2;
case 0xE:
- return B43_OFDM_RATE_18MB;
+ return base + 3;
case 0x9:
- return B43_OFDM_RATE_24MB;
+ return base + 4;
case 0xD:
- return B43_OFDM_RATE_36MB;
+ return base + 5;
case 0x8:
- return B43_OFDM_RATE_48MB;
+ return base + 6;
case 0xC:
- return B43_OFDM_RATE_54MB;
+ return base + 7;
}
B43_WARN_ON(1);
- return 0;
+ return -1;
}
u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
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;
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)
* 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;
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
/* 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);
/* 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) ||
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,
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;
u16 phystat0, phystat3, chanstat, mactime;
u32 macstat;
u16 chanid;
+ u16 phytype;
u8 jssi;
int padding;
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++;
}
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;
/* 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;
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 */
/* 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
#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 {
} __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);
#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
#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
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)" \
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" \
+++ /dev/null
-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
--- /dev/null
+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;
+++ /dev/null
----
- 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 */
+++ /dev/null
----
- 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 */
+++ /dev/null
----
- 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;
+++ /dev/null
-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;
- }
+++ /dev/null
-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;
- }
+++ /dev/null
----
- 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;
+++ /dev/null
----
- 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;
+++ /dev/null
----
- 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;
+++ /dev/null
----
- 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;
+++ /dev/null
-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(¶ms, 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, ¶ms);
-+ 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 */
+++ /dev/null
-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,
- };
+++ /dev/null
-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(¶ms, 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, ¶ms);
-+ 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,
+++ /dev/null
-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(¶ms, 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, ¶ms);
-+ 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 */
+++ /dev/null
-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));
+++ /dev/null
-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(¶ms, 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],
-+ ¶ms.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, ¶ms.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, ¶ms);
-+ 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(¶ms, 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],
-+ ¶ms.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, ¶ms.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, ¶ms);
-+ 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 */
+++ /dev/null
-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,
- };
+++ /dev/null
-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;
- }
-
- /*
+++ /dev/null
-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,
- };
#define IEEE80211_STYPE_ACTION 0x00D0
/* control */
+#define IEEE80211_STYPE_BACK_REQ 0x0080
+#define IEEE80211_STYPE_BACK 0x0090
#define IEEE80211_STYPE_PSPOLL 0x00A0
#define IEEE80211_STYPE_RTS 0x00B0
#define IEEE80211_STYPE_CTS 0x00C0
/* miscellaneous IEEE 802.11 constants */
-#define IEEE80211_MAX_FRAG_THRESHOLD 2346
-#define IEEE80211_MAX_RTS_THRESHOLD 2347
+#define IEEE80211_MAX_FRAG_THRESHOLD 2352
+#define IEEE80211_MAX_RTS_THRESHOLD 2353
#define IEEE80211_MAX_AID 2007
#define IEEE80211_MAX_TIM_LEN 251
-#define IEEE80211_MAX_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
6.2.1.1.2.
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+ 802.11e clarifies the figure in section 7.1.2. The frame body is
+ up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
+#define IEEE80211_MAX_DATA_LEN 2304
+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
+#define IEEE80211_MAX_FRAME_LEN 2352
#define IEEE80211_MAX_SSID_LEN 32
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;
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
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,
};
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,
};
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,
/* 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,
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
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
/**
* enum nl80211_commands - supported nl80211 commands
*
* either a dump request on a %NL80211_ATTR_WIPHY or a specific get
* on an %NL80211_ATTR_IFINDEX is supported.
* @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
- %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
* to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
* userspace to request deletion of a virtual interface, then requires
* attribute %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
+ * %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ * attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
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 */
* @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
*/
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
*
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 */
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;
*
* @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 */
* 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_ */
};
/**
* @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,
* 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 {
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 */
#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
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 */
};
* 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,
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,
};
/**
* 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;
};
*
* @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,
};
/**
*
* @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;
*
* @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),
};
/**
*
* @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;
};
/**
IEEE80211_IF_TYPE_VLAN,
};
+/**
+ * struct ieee80211_vif - per-interface data
+ *
+ * Data in this structure is continually present for driver
+ * use during the life of a virtual interface.
+ *
+ * @type: type of this virtual interface
+ * @drv_priv: data area for driver use, will always be aligned to
+ * sizeof(void *).
+ */
+struct ieee80211_vif {
+ enum ieee80211_if_types type;
+ /* must be last */
+ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
/**
* struct ieee80211_if_init_conf - initial configuration of an interface
*
- * @if_id: internal interface ID. This number has no particular meaning to
- * drivers and the only allowed usage is to pass it to
- * ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
- * This field is not valid for monitor interfaces
- * (interfaces of %IEEE80211_IF_TYPE_MNTR type).
+ * @vif: pointer to a driver-use per-interface structure. The pointer
+ * itself is also used for various functions including
+ * ieee80211_beacon_get() and ieee80211_get_buffered_bc().
* @type: one of &enum ieee80211_if_types constants. Determines the type of
* added/removed interface.
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
* in pure monitor mode.
*/
struct ieee80211_if_init_conf {
- int if_id;
enum ieee80211_if_types type;
+ struct ieee80211_vif *vif;
void *mac_addr;
};
u8 key[0];
};
-#define IEEE80211_SEQ_COUNTER_RX 0
-#define IEEE80211_SEQ_COUNTER_TX 1
-
/**
* enum set_key_cmd - key command
*
* %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,
};
/**
* @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.
*
*
* @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;
};
/**
- * 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
*
* @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.
* 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)
*
* @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.
* @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,
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,
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,
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);
};
/**
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
#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
#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
/**
* 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
* 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.
* 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);
/**
* 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.
*
* 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.
* 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);
/**
* 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.
*
* 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
* 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);
/**
*/
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 */
--- /dev/null
+#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 */
config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
- depends on EXPERIMENTAL
select CRYPTO
select CRYPTO_ECB
select CRYPTO_ARC4
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"
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
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
-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 \
ieee80211_iface.o \
ieee80211_rate.o \
michael.o \
- regdomain.o \
tkip.o \
aes_ccm.o \
cfg.o \
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)
* 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"
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);
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);
/*
* 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)
}
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;
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)
return -ENODEV;
/* we're under RTNL */
- dev = __dev_get_by_index(ifindex);
+ dev = __dev_get_by_index(&init_net, ifindex);
if (!dev)
return 0;
}
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;
return -ENODEV;
/* we're under RTNL */
- dev = __dev_get_by_index(ifindex);
+ dev = __dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENODEV;
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(¶ms, 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, ¶ms);
+ 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;
}
.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,
};
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) \
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",
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",
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);
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;
void debugfs_hw_del(struct ieee80211_local *local)
{
- DEBUGFS_DEL(channel);
DEBUGFS_DEL(frequency);
DEBUGFS_DEL(antenna_sel_tx);
DEBUGFS_DEL(antenna_sel_rx);
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);
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);
}
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) \
/* 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);
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);
}
__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);
{
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);
{
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);
}
{
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)
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);
{
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);
{
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);
}
{
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)
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;
}
#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, \
}
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);
{
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" : "",
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);
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;
DEBUGFS_ADD(wme_rx_queue);
DEBUGFS_ADD(wme_tx_queue);
#endif
+ DEBUGFS_ADD(agg_status);
}
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;
{
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);
#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"
#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.
/* 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;
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;
/*
* 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;
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)
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
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);
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);
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:
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);
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);
}
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);
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)
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)
{
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;
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 */
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 */
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)
{
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);
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);
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,
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))) {
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);
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);
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;
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);
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
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);
/* 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;
}
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);
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;
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);
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;
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)
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));
}
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);
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",
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();
}
+++ /dev/null
-/*
- * 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 */
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
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;
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;
};
-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 */
/* 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;
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) */
} tx;
struct {
struct ieee80211_rx_status *status;
+ struct ieee80211_rate *rate;
int sent_ps_buffered;
int queue;
int load;
#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;
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;
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 */
#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,
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 */
unsigned long request;
struct sk_buff_head skb_queue;
- int key_management_enabled;
unsigned long last_probe;
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
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;
};
/* 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;
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;
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 {
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;
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;
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;
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 {
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;
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 */
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 */
* 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 */
#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;
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;
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;
#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)
{
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 ||
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;
/* 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);
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);
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);
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);
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,
/* 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);
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;
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);
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
/* 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:
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);
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",
ieee80211_if_sdata_deinit(sdata);
- switch (sdata->type) {
+ switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_INVALID:
/* cannot happen */
WARN_ON(1);
}
}
- 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--;
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);
#include <net/mac80211.h>
#include "ieee80211_i.h"
+#include "ieee80211_led.h"
#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
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;
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;
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;
}
{
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);
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;
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;
}
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) {
return -EINVAL;
}
- if (type == sdata->type)
+ if (type == sdata->vif.type)
return 0;
if (netif_running(dev))
return -EBUSY;
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;
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);
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;
}
{
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;
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)
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);
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;
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;
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,
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;
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;
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);
{
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;
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 */
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,
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;
}
{
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,
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) {
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;
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;
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;
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;
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);
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);
}
}
+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);
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
bool associated)
{
}
+static inline void ieee80211_led_radio(struct ieee80211_local *local,
+ bool enabled)
+{
+}
static inline void ieee80211_led_init(struct ieee80211_local *local)
{
}
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);
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);
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;
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;
}
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);
local->rate_ctrl = NULL;
rate_control_put(ref);
}
+
#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);
* 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);
}
#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 */
*/
/* TODO:
- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
* order BSS list by RSSI(?) ("quality of AP")
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
* SSID)
#define ERP_INFO_USE_PROTECTION BIT(1)
+/* mgmt header + 1 byte action code */
+#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
+
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/* next values represent the buffer size for A-MPDU frame.
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
u8 *ssid, size_t ssid_len);
static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
+ u8 *ssid, u8 ssid_len);
static void ieee80211_rx_bss_put(struct net_device *dev,
struct ieee80211_sta_bss *bss);
static int ieee80211_sta_find_ibss(struct net_device *dev,
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;
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));
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:
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;
}
-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)
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);
}
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,
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);
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;
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 +
}
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;
*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);
}
}
*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;
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);
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
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;
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
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);
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;
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]++;
pos = skb_put(skb, 1);
supp_rates[1]++;
}
- *pos = rate->rate / 5;
+ *pos = rate->bitrate / 5;
}
ieee80211_sta_tx(dev, skb, 0);
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);
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,
{
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;
}
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
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);
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);
}
-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",
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",
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;
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) {
" 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;
}
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);
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);
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;
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? */
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;
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;
}
kfree(bss->wpa_ie);
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
+ kfree(bss->ht_ie);
kfree(bss);
}
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;
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;
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),
#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 +
[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);
}
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 {
#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);
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) {
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;
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;
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);
}
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;
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)
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;
}
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)
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;
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);
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;
}
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);
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;
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;
}
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 |
{
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)
}
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;
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);
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);
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;
}
*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;
}
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;
}
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) {
{
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. */
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);
}
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;
|| !(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;
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
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
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);
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;
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)
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;
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);
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) {
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);
}
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 &&
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)
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);
}
* 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;
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) {
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);
}
} 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);
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;
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;
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);
}
}
- 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;
}
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);
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);
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))
* 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)
{
const u8 *addr;
int ret;
+ DECLARE_MAC_BUF(mac);
if (!key->local->ops->set_key)
return;
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;
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;
}
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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/compiler.h>
+#include <linux/module.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
/* This is a minimal implementation of TX rate controlling that can be used
* as the default when no improved mechanisms are available. */
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP 15
#define RATE_CONTROL_EMERG_DEC 2
#define RATE_CONTROL_INTERVAL (HZ / 20)
#define RATE_CONTROL_MIN_TX 10
-MODULE_ALIAS("rc80211_default");
-
static void rate_control_rate_inc(struct ieee80211_local *local,
struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hw_mode *mode;
- int i = sta->txrate;
+ struct ieee80211_supported_band *sband;
+ int i = sta->txrate_idx;
int maxrate;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
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;
}
}
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) {
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;
};
} 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;
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,
}
-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];
}
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);
}
}
#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,
#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
+++ /dev/null
-/*
- * 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;
-}
-
#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
*
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;
}
*/
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;
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;
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;
* 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;
}
/* 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);
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) {
}
-/* 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;
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 */
/* 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;
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;
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.
*
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) &&
|| !(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;
/*
*/
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);
*/
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,
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 */
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)
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 */
}
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)
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) {
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);
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;
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.
}
if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
* 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 *
#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);
}
return NULL;
}
-static ieee80211_txrx_result
+static ieee80211_rx_result
ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
{
struct ieee80211_hdr *hdr;
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);
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
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.
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]++;
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);
}
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);
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))) {
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) {
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 */
}
#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;
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);
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);
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):
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:
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 &&
} else {
struct ethhdr *ehdr;
__be16 len;
+
skb_pull(skb, hdrlen);
len = htons(skb->len);
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_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)
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)
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;
}
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
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;
}
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;
}
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,
* 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,
{
int multicast = is_multicast_ether_addr(hdr->addr1);
- switch (sdata->type) {
+ switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_STA:
if (!bssid)
return 0;
}
/*
- * 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;
/*
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);
#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"
}
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
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);
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)
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
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
{
struct sk_buff *skb;
struct ieee80211_local *local = sta->local;
+ DECLARE_MAC_BUF(mac);
might_sleep();
}
#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);
{
unsigned long flags;
struct sk_buff *skb;
+ DECLARE_MAC_BUF(mac);
if (skb_queue_empty(&sta->ps_tx_buf))
return;
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;
}
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);
}
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;
#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;
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 */
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;
struct dentry *wme_rx_queue;
struct dentry *wme_tx_queue;
#endif
+ struct dentry *agg_status;
} debugfs;
#endif
};
}
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);
(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 */
#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[
#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>
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) {
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 */
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):
* 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
* 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
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;
/* 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
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;
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
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);
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) >=
} 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;
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
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);
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;
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;
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)
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);
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:
/* 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)) {
* 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;
* 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
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) {
}
}
- /*
- * 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
/* 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;
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;
}
}
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,
* 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)
{
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;
* 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;
}
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) {
* on transmission
*/
if (skb->len < (iterator.max_length + FCS_LEN))
- return TXRX_DROP;
+ return TX_DROP;
skb_trim(skb, skb->len - FCS_LEN);
}
}
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return TXRX_DROP;
+ return TX_DROP;
/*
* remove the radiotap header
*/
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,
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;
/* 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
}
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,
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;
return -ENODEV;
/* initialises tx with control */
__ieee80211_tx_prepare(tx, skb, dev, control);
+ dev_put(dev);
return 0;
}
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;
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));
/* 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;
}
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;
}
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;
} 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);
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);
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;
}
}
- 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);
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)) {
/* 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;
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);
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++;
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)
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)
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;
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--;
*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;
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);
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)
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)
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);
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 */
}
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;
}
#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"
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;
}
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;
}
}
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;
* DIV_ROUND_UP() operations.
*/
- if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
/*
* OFDM:
*
}
/* 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);
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);
#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"
*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);
}
__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));
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;
}
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);
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)
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) {
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;
}
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 */
#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)
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)
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)) {
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;
}
*/
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)) {
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);
/* 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 */
}
}
+ /* reserve all legacy QoS queues */
+ for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+ set_bit(i, &q->qdisc_pool);
+
return err;
}
{
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);
+ }
+}
#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;
#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
{
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;
}
-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;
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) &&
!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) {
GFP_ATOMIC))) {
printk(KERN_DEBUG "%s: failed to allocate more memory "
"for Michael MIC\n", tx->dev->name);
- return TXRX_DROP;
+ return TX_DROP;
}
}
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;
u8 mic[MICHAEL_MIC_LEN];
struct sk_buff *skb = rx->skb;
int authenticator = 1, wpa_test = 0;
+ DECLARE_MAC_BUF(mac);
fc = rx->fc;
* 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;
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 */
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;
}
}
-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);
!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;
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) {
* 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 */
&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 */
memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
skb_pull(skb, TKIP_IV_LEN);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
}
-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);
/* 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;
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)) {
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;
}
}
memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
skb_pull(skb, CCMP_HDR_LEN);
- return TXRX_CONTINUE;
+ return RX_CONTINUE;
}
-
#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 */
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"
+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
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 =
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) {
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);
{
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);
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 */
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;
[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 */
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)
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:
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]);
}
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:
struct cfg80211_registered_device *drv;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+ u32 flags;
if (!info->attrs[NL80211_ATTR_IFNAME])
return -EINVAL;
}
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:
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(¶ms, 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, ¶ms);
+ 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(¶ms, 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, ¶ms);
+ 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(¶ms, 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],
+ ¶ms.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, ¶ms.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, ¶ms);
+ 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(¶ms, 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],
+ ¶ms.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, ¶ms.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, ¶ms);
+ 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,
.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 */
--- /dev/null
+/*
+ * 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 ®dom_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);
+}
}
#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;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);