diff options
Diffstat (limited to 'package')
103 files changed, 16995 insertions, 10167 deletions
diff --git a/package/b43/Makefile b/package/b43/Makefile index c4cc91f5cf..e47d5165eb 100644 --- a/package/b43/Makefile +++ b/package/b43/Makefile @@ -23,11 +23,11 @@ PKG_FWV4_SOURCE_URL:=http://downloads.openwrt.org/sources/ PKG_FWV4_MD5SUM:=a7d8dde3ce474c361143b83e1d9890b1 PKG_FWCUTTER_NAME:=b43-fwcutter -PKG_FWCUTTER_VERSION=008 +PKG_FWCUTTER_VERSION=011 PKG_FWCUTTER_SOURCE:=$(PKG_FWCUTTER_NAME)-$(PKG_FWCUTTER_VERSION).tar.bz2 -PKG_FWCUTTER_SOURCE_URL:=http://download.berlios.de/bcm43xx/ -PKG_FWCUTTER_MD5SUM:=3f7fbf4f8dcd296c6d1b0d42eab0f9ac +PKG_FWCUTTER_SOURCE_URL:=http://bu3sch.de/b43/fwcutter/ +PKG_FWCUTTER_MD5SUM:=3db2f4de85a459451f5b391cf67a8d44 define KernelPackage/b43 SUBMENU:=Wireless Drivers @@ -43,7 +43,6 @@ endef EXTRA_KCONFIG:= \ CONFIG_B43=m \ - CONFIG_B43_DMA=y \ $(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \ @@ -73,6 +72,8 @@ define Build/Prepare $(CP) ./src/* $(PKG_BUILD_DIR)/ tar xjf "$(DL_DIR)/$(PKG_FWV4_SOURCE)" -C "$(PKG_BUILD_DIR)" tar xjf "$(DL_DIR)/$(PKG_FWCUTTER_SOURCE)" -C "$(PKG_BUILD_DIR)" + $(Build/Patch) + $(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used) endef define Build/Configure diff --git a/package/b43/src/Kconfig b/package/b43/src/Kconfig index e3c573e56b..1a2141dabd 100644 --- a/package/b43/src/Kconfig +++ b/package/b43/src/Kconfig @@ -61,16 +61,28 @@ config B43_PCMCIA If unsure, say N. -# LED support +config B43_NPHY + bool "Pre IEEE 802.11n support (BROKEN)" + depends on B43 && EXPERIMENTAL && BROKEN + ---help--- + Support for the IEEE 802.11n draft. + + THIS IS BROKEN AND DOES NOT WORK YET. + + SAY N. + +# This config option automatically enables b43 LEDS support, +# if it's possible. config B43_LEDS bool - depends on B43 && MAC80211_LEDS + depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) default y -# RFKILL support +# This config option automatically enables b43 RFKILL support, +# if it's possible. config B43_RFKILL bool - depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV + depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) default y config B43_DEBUG @@ -81,51 +93,3 @@ config B43_DEBUG Say Y, if you want to find out why the driver does not work for you. - -config B43_DMA - bool - depends on B43 -config B43_PIO - bool - depends on B43 - -choice - prompt "Broadcom 43xx data transfer mode" - depends on B43 - default B43_DMA_AND_PIO_MODE - -config B43_DMA_AND_PIO_MODE - bool "DMA + PIO" - select B43_DMA - select B43_PIO - ---help--- - Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) - data transfer modes. - The actually used mode is selectable through the module - parameter "pio". If the module parameter is pio=0, DMA is used. - Otherwise PIO is used. DMA is default. - - If unsure, choose this option. - -config B43_DMA_MODE - bool "DMA (Direct Memory Access) only" - select B43_DMA - ---help--- - Only include Direct Memory Access (DMA). - This reduces the size of the driver module, by omitting the PIO code. - -config B43_PIO_MODE - bool "PIO (Programmed I/O) only" - select B43_PIO - ---help--- - Only include Programmed I/O (PIO). - This reduces the size of the driver module, by omitting the DMA code. - Please note that PIO transfers are slow (compared to DMA). - - Also note that not all devices of the 43xx series support PIO. - The 4306 (Apple Airport Extreme and others) supports PIO, while - the 4318 is known to _not_ support PIO. - - Only use PIO, if DMA does not work for you. - -endchoice diff --git a/package/b43/src/Makefile b/package/b43/src/Makefile index 485e59e2df..ac1329dba0 100644 --- a/package/b43/src/Makefile +++ b/package/b43/src/Makefile @@ -1,20 +1,16 @@ -# b43 core b43-y += main.o b43-y += tables.o +b43-y += tables_nphy.o b43-y += phy.o +b43-y += nphy.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o -# b43 RFKILL button support +b43-y += wa.o +b43-y += dma.o b43-$(CONFIG_B43_RFKILL) += rfkill.o -# b43 LED support b43-$(CONFIG_B43_LEDS) += leds.o -# b43 PCMCIA support b43-$(CONFIG_B43_PCMCIA) += pcmcia.o -# b43 debugging b43-$(CONFIG_B43_DEBUG) += debugfs.o -# b43 DMA and PIO -b43-$(CONFIG_B43_DMA) += dma.o -b43-$(CONFIG_B43_PIO) += pio.o obj-$(CONFIG_B43) += b43.o diff --git a/package/b43/src/b43.h b/package/b43/src/b43.h index a28ad230d6..0dc1aaf46b 100644 --- a/package/b43/src/b43.h +++ b/package/b43/src/b43.h @@ -35,8 +35,8 @@ #define B43_MMIO_DMA4_IRQ_MASK 0x44 #define B43_MMIO_DMA5_REASON 0x48 #define B43_MMIO_DMA5_IRQ_MASK 0x4C -#define B43_MMIO_MACCTL 0x120 -#define B43_MMIO_STATUS2_BITFIELD 0x124 +#define B43_MMIO_MACCTL 0x120 /* MAC control */ +#define B43_MMIO_MACCMD 0x124 /* MAC command */ #define B43_MMIO_GEN_IRQ_REASON 0x128 #define B43_MMIO_GEN_IRQ_MASK 0x12C #define B43_MMIO_RAM_CONTROL 0x130 @@ -50,6 +50,9 @@ #define B43_MMIO_XMITSTAT_1 0x174 #define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ #define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ +#define B43_MMIO_TSF_CFP_REP 0x188 +#define B43_MMIO_TSF_CFP_START 0x18C +#define B43_MMIO_TSF_CFP_MAXDUR 0x190 /* 32-bit DMA */ #define B43_MMIO_DMA32_BASE0 0x200 @@ -65,11 +68,6 @@ #define B43_MMIO_DMA64_BASE3 0x2C0 #define B43_MMIO_DMA64_BASE4 0x300 #define B43_MMIO_DMA64_BASE5 0x340 -/* PIO */ -#define B43_MMIO_PIO1_BASE 0x300 -#define B43_MMIO_PIO2_BASE 0x310 -#define B43_MMIO_PIO3_BASE 0x320 -#define B43_MMIO_PIO4_BASE 0x330 #define B43_MMIO_PHY_VER 0x3E0 #define B43_MMIO_PHY_RADIO 0x3E2 @@ -88,6 +86,8 @@ #define B43_MMIO_RADIO_HWENABLED_LO 0x49A #define B43_MMIO_GPIO_CONTROL 0x49C #define B43_MMIO_GPIO_MASK 0x49E +#define B43_MMIO_TSF_CFP_START_LOW 0x604 +#define B43_MMIO_TSF_CFP_START_HIGH 0x606 #define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ #define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ @@ -170,14 +170,17 @@ enum { #define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ #define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ #define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ -/* SHM_SHARED beacon variables */ +/* SHM_SHARED beacon/AP variables */ #define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ #define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ #define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ #define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ +#define B43_SHM_SH_DTIMP 0x0012 /* DTIP period */ +#define B43_SHM_SH_MCASTCOOKIE 0x00A8 /* Last bcast/mcast frame ID */ #define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ +#define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */ /* SHM_SHARED ACK/CTS control */ #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ /* SHM_SHARED probe response variables */ @@ -273,6 +276,8 @@ enum { #define B43_PHYTYPE_A 0x00 #define B43_PHYTYPE_B 0x01 #define B43_PHYTYPE_G 0x02 +#define B43_PHYTYPE_N 0x04 +#define B43_PHYTYPE_LP 0x05 /* PHYRegisters */ #define B43_PHY_ILT_A_CTRL 0x0072 @@ -319,17 +324,29 @@ enum { #define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */ #define B43_MACCTL_GMODE 0x80000000 /* G Mode */ -/* 802.11 core specific TM State Low flags */ +/* MAC Command bitfield */ +#define B43_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */ +#define B43_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */ +#define B43_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */ +#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */ +#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */ + +/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */ #define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ -#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */ +#define B43_TMSLOW_PHYCLKSPEED 0x00C00000 /* PHY clock speed mask (N-PHY only) */ +#define B43_TMSLOW_PHYCLKSPEED_40MHZ 0x00000000 /* 40 MHz PHY */ +#define B43_TMSLOW_PHYCLKSPEED_80MHZ 0x00400000 /* 80 MHz PHY */ +#define B43_TMSLOW_PHYCLKSPEED_160MHZ 0x00800000 /* 160 MHz PHY */ +#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select (rev >= 5) */ #define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */ #define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ #define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ -/* 802.11 core specific TM State High flags */ +/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */ +#define B43_TMSHIGH_DUALBAND_PHY 0x00080000 /* Dualband PHY available */ #define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */ -#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */ -#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */ +#define B43_TMSHIGH_HAVE_5GHZ_PHY 0x00020000 /* 5 GHz PHY available (rev >= 5) */ +#define B43_TMSHIGH_HAVE_2GHZ_PHY 0x00010000 /* 2.4 GHz PHY available (rev >= 5) */ /* Generic-Interrupt reasons. */ #define B43_IRQ_MAC_SUSPENDED 0x00000001 @@ -391,6 +408,8 @@ enum { #define B43_DEFAULT_SHORT_RETRY_LIMIT 7 #define B43_DEFAULT_LONG_RETRY_LIMIT 4 +#define B43_PHY_TX_BADNESS_LIMIT 1000 + /* Max size of a security key */ #define B43_SEC_KEYSIZE 16 /* Security algorithms. */ @@ -443,10 +462,6 @@ struct b43_phy { u8 possible_phymodes; /* GMODE bit enabled? */ bool gmode; - /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ -#define B43_MAX_PHYHWMODES 2 - struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES]; /* Analog Type */ u8 analog; @@ -460,7 +475,6 @@ struct b43_phy { u16 radio_ver; /* Radio version */ u8 radio_rev; /* Radio revision */ - bool locked; /* Only used in b43_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ @@ -497,11 +511,6 @@ struct b43_phy { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* PHY lock for core.rev < 3 - * This lock is only used by b43_phy_{un}lock() - */ - spinlock_t lock; - /* Desired TX power level (in dBm). * This is set by the user and adjusted in b43_phy_xmitpower(). */ u8 power_level; @@ -512,9 +521,7 @@ struct b43_phy { struct b43_bbatt bbatt; struct b43_rfatt rfatt; u8 tx_control; /* B43_TXCTL_XXX */ -#ifdef CONFIG_B43_DEBUG - bool manual_txpower_control; /* Manual TX-power control enabled? */ -#endif + /* Hardware Power Control enabled? */ bool hardware_power_control; @@ -542,6 +549,26 @@ struct b43_phy { u16 lofcal; u16 initval; //FIXME rename? + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + + /* The device does address auto increment for the OFDM tables. + * We cache the previously used address here and omit the address + * write on the next table access, if possible. */ + u16 ofdmtab_addr; /* The address currently set in hardware. */ + enum { /* The last data flow direction. */ + B43_OFDMTAB_DIRECTION_UNKNOWN = 0, + B43_OFDMTAB_DIRECTION_READ, + B43_OFDMTAB_DIRECTION_WRITE, + } ofdmtab_addr_direction; + +#if B43_DEBUG + /* Manual TX-power control enabled? */ + bool manual_txpower_control; + /* PHY registers locked by b43_phy_lock()? */ + bool phy_locked; +#endif /* B43_DEBUG */ }; /* Data structures for DMA transmission, per 80211 core. */ @@ -557,14 +584,6 @@ struct b43_dma { struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ }; -/* Data structures for PIO transmission, per 80211 core. */ -struct b43_pio { - struct b43_pioqueue *queue0; - struct b43_pioqueue *queue1; - struct b43_pioqueue *queue2; - struct b43_pioqueue *queue3; -}; - /* Context information for a noise calculation (Link Quality). */ struct b43_noise_calculation { u8 channel_at_start; @@ -597,18 +616,18 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; - spinlock_t irq_lock; struct mutex mutex; + spinlock_t irq_lock; + /* Lock for LEDs access. */ spinlock_t leds_lock; + /* Lock for SHM access. */ + spinlock_t shm_lock; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface from the ieee80211 - * subsystem. Do not modify. - */ - int if_id; + struct ieee80211_vif *vif; /* The MAC address of the operating interface. */ u8 mac_addr[ETH_ALEN]; /* Current BSSID */ @@ -632,18 +651,33 @@ struct b43_wl { /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; + + bool radiotap_enabled; + + /* The beacon we are currently using (AP or IBSS mode). + * This beacon stuff is protected by the irq_lock. */ + struct sk_buff *current_beacon; + bool beacon0_uploaded; + bool beacon1_uploaded; +}; + +/* In-memory representation of a cached microcode file. */ +struct b43_firmware_file { + const char *filename; + const struct firmware *data; }; /* Pointers to the firmware data and meta information about it. */ struct b43_firmware { /* Microcode */ - const struct firmware *ucode; + struct b43_firmware_file ucode; /* PCM code */ - const struct firmware *pcm; + struct b43_firmware_file pcm; /* Initial MMIO values for the firmware */ - const struct firmware *initvals; + struct b43_firmware_file initvals; /* Initial MMIO values for the firmware, band-specific */ - const struct firmware *initvals_band; + struct b43_firmware_file initvals_band; + /* Firmware revision */ u16 rev; /* Firmware patchlevel */ @@ -681,21 +715,16 @@ struct b43_wldev { /* Saved init status for handling suspend. */ int suspend_init_status; - bool __using_pio; /* Internal, use b43_using_pio(). */ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ - bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */ - bool short_preamble; /* TRUE, if short preamble is enabled. */ + bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ /* PHY/Radio device. */ struct b43_phy phy; - union { - /* DMA engines. */ - struct b43_dma dma; - /* PIO engines. */ - struct b43_pio pio; - }; + + /* DMA engines. */ + struct b43_dma dma; /* Various statistics about the physical device. */ struct b43_stats stats; @@ -730,9 +759,6 @@ struct b43_wldev { u8 max_nr_keys; struct b43_key key[58]; - /* Cached beacon template while uploading the template. */ - struct sk_buff *cached_beacon; - /* Firmware data */ struct b43_firmware fw; @@ -750,28 +776,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) return hw->priv; } -/* Helper function, which returns a boolean. - * TRUE, if PIO is used; FALSE, if DMA is used. - */ -#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return dev->__using_pio; -} -#elif defined(CONFIG_B43_DMA) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return 0; -} -#elif defined(CONFIG_B43_PIO) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return 1; -} -#else -# error "Using neither DMA nor PIO? Confused..." -#endif - static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); diff --git a/package/b43/src/debugfs.c b/package/b43/src/debugfs.c index 734e70e1a0..e38ed0fe72 100644 --- a/package/b43/src/debugfs.c +++ b/package/b43/src/debugfs.c @@ -34,7 +34,6 @@ #include "main.h" #include "debugfs.h" #include "dma.h" -#include "pio.h" #include "xmit.h" @@ -128,7 +127,7 @@ static ssize_t shm_read_file(struct b43_wldev *dev, __le16 *le16buf = (__le16 *)buf; for (i = 0; i < 0x1000; i++) { - if (bufsize <= 0) + if (bufsize < sizeof(tmp)) break; tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); le16buf[i] = cpu_to_le16(tmp); @@ -223,8 +222,6 @@ out: static int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) { - unsigned long phy_flags; - if (dev->phy.type != B43_PHYTYPE_G) return -ENODEV; if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { @@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev, dev->phy.tx_control |= B43_TXCTL_PA2DB; if (pa3db) dev->phy.tx_control |= B43_TXCTL_PA3DB; - b43_phy_lock(dev, phy_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_set_txpower_g(dev, &dev->phy.bbatt, &dev->phy.rfatt, dev->phy.tx_control); b43_radio_unlock(dev); - b43_phy_unlock(dev, phy_flags); + b43_phy_unlock(dev); } return 0; @@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_wldev *dev; struct b43_debugfs_fops *dfops; struct b43_dfs_file *dfile; - ssize_t ret; + ssize_t uninitialized_var(ret); char *buf; const size_t bufsize = 1024 * 128; const size_t buforder = get_order(bufsize); diff --git a/package/b43/src/dma.c b/package/b43/src/dma.c index 5e8f8ac0f1..3dfb28a34b 100644 --- a/package/b43/src/dma.c +++ b/package/b43/src/dma.c @@ -37,6 +37,8 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/skbuff.h> +#include <linux/etherdevice.h> + /* 32bit DMA ops. */ static @@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring, addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) >> SSB_DMA_TRANSLATION_SHIFT; - addrhi |= ssb_dma_translation(ring->dev->dev); + addrhi |= (ssb_dma_translation(ring->dev->dev) << 1); if (slot == ring->nr_slots - 1) ctl0 |= B43_DMA64_DCTL0_DTABLEEND; if (start) @@ -315,29 +317,27 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, case 3: ring = dev->dma.tx_ring0; break; - case 4: - ring = dev->dma.tx_ring4; - break; - case 5: - ring = dev->dma.tx_ring5; - break; } return ring; } -/* Bcm43xx-ring to mac80211-queue mapping */ +/* b43-ring to mac80211-queue mapping */ static inline int txring_to_priority(struct b43_dmaring *ring) { - static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, }; + static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; + unsigned int index; /*FIXME: have only one queue, for now */ return 0; - return idx_to_prio[ring->index]; + index = ring->index; + if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) + index = 0; + return idx_to_prio[index]; } -u16 b43_dmacontroller_base(int dma64bit, int controller_idx) +static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) { static const u16 map64[] = { B43_MMIO_DMA64_BASE0, @@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx) B43_MMIO_DMA32_BASE5, }; - if (dma64bit) { + if (type == B43_DMA_64BIT) { B43_WARN_ON(!(controller_idx >= 0 && controller_idx < ARRAY_SIZE(map64))); return map64[controller_idx]; @@ -426,9 +426,21 @@ static inline static int alloc_ringmemory(struct b43_dmaring *ring) { struct device *dev = ring->dev->dev->dev; - + gfp_t flags = GFP_KERNEL; + + /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K + * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing + * has shown that 4K is sufficient for the latter as long as the buffer + * does not cross an 8K boundary. + * + * For unknown reasons - possibly a hardware error - the BCM4311 rev + * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, + * which accounts for the GFP_DMA flag below. + */ + if (ring->type == B43_DMA_64BIT) + flags |= GFP_DMA; ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; @@ -447,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring) } /* Reset the RX DMA channel */ -int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, + enum b43_dmatype type) { int i; u32 value; @@ -455,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) might_sleep(); - offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL; + offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL; b43_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS; + offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS : + B43_DMA32_RXSTATUS; value = b43_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43_DMA_64BIT) { value &= B43_DMA64_RXSTAT; if (value == B43_DMA64_RXSTAT_DISABLED) { i = -1; @@ -483,8 +497,9 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) return 0; } -/* Reset the RX DMA channel */ -int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +/* Reset the TX DMA channel */ +static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, + enum b43_dmatype type) { int i; u32 value; @@ -493,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) might_sleep(); for (i = 0; i < 10; i++) { - offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS : + B43_DMA32_TXSTATUS; value = b43_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43_DMA_64BIT) { value &= B43_DMA64_TXSTAT; if (value == B43_DMA64_TXSTAT_DISABLED || value == B43_DMA64_TXSTAT_IDLEWAIT || @@ -510,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) } msleep(1); } - offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL; + offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL; b43_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS : + B43_DMA32_TXSTATUS; value = b43_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43_DMA_64BIT) { value &= B43_DMA64_TXSTAT; if (value == B43_DMA64_TXSTAT_DISABLED) { i = -1; @@ -540,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) return 0; } +/* Check if a DMA mapping address is invalid. */ +static bool b43_dma_mapping_error(struct b43_dmaring *ring, + dma_addr_t addr, + size_t buffersize) +{ + if (unlikely(dma_mapping_error(addr))) + return 1; + + switch (ring->type) { + case B43_DMA_30BIT: + if ((u64)addr + buffersize > (1ULL << 30)) + return 1; + break; + case B43_DMA_32BIT: + if ((u64)addr + buffersize > (1ULL << 32)) + return 1; + break; + case B43_DMA_64BIT: + /* Currently we can't have addresses beyond + * 64bit in the kernel. */ + break; + } + + /* The address is OK. */ + return 0; +} + static int setup_rx_descbuffer(struct b43_dmaring *ring, struct b43_dmadesc_generic *desc, struct b43_dmadesc_meta *meta, gfp_t gfp_flags) @@ -555,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, if (unlikely(!skb)) return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); - if (dma_mapping_error(dmaaddr)) { + if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { /* ugh. try to realloc in zone_dma */ gfp_flags |= GFP_DMA; @@ -568,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, ring->rx_buffersize, 0); } - if (dma_mapping_error(dmaaddr)) { + if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { dev_kfree_skb_any(skb); return -EIO; } @@ -633,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) u32 trans = ssb_dma_translation(ring->dev->dev); if (ring->tx) { - if (ring->dma64) { + if (ring->type == B43_DMA_64BIT) { u64 ringbase = (u64) (ring->dmabase); addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) @@ -647,7 +691,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA64_TXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); + | (trans << 1)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -665,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) err = alloc_initial_descbuffers(ring); if (err) goto out; - if (ring->dma64) { + if (ring->type == B43_DMA_64BIT) { u64 ringbase = (u64) (ring->dmabase); addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) @@ -680,8 +724,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA64_RXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); - b43_dma_write(ring, B43_DMA64_RXINDEX, 200); + | (trans << 1)); + b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc64)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -695,11 +740,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA32_RXRING, (ringbase & ~SSB_DMA_TRANSLATION_MASK) | trans); - b43_dma_write(ring, B43_DMA32_RXINDEX, 200); + b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc32)); } } - out: +out: return err; } @@ -708,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring) { if (ring->tx) { b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base, - ring->dma64); - if (ring->dma64) { + ring->type); + if (ring->type == B43_DMA_64BIT) { b43_dma_write(ring, B43_DMA64_TXRINGLO, 0); b43_dma_write(ring, B43_DMA64_TXRINGHI, 0); } else b43_dma_write(ring, B43_DMA32_TXRING, 0); } else { b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base, - ring->dma64); - if (ring->dma64) { + ring->type); + if (ring->type == B43_DMA_64BIT) { b43_dma_write(ring, B43_DMA64_RXRINGLO, 0); b43_dma_write(ring, B43_DMA64_RXRINGHI, 0); } else @@ -772,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev) static struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, int controller_index, - int for_tx, int dma64) + int for_tx, + enum b43_dmatype type) { struct b43_dmaring *ring; int err; @@ -782,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) goto out; + ring->type = type; nr_slots = B43_RXRING_SLOTS; if (for_tx) @@ -793,7 +841,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_ring; if (for_tx) { ring->txhdr_cache = kcalloc(nr_slots, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), GFP_KERNEL); if (!ring->txhdr_cache) goto err_kfree_meta; @@ -801,39 +849,38 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, /* test for ability to dma to txhdr_cache */ dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), DMA_TO_DEVICE); - if (dma_mapping_error(dma_test)) { + if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) { /* ugh realloc */ kfree(ring->txhdr_cache); ring->txhdr_cache = kcalloc(nr_slots, - sizeof(struct - b43_txhdr_fw4), + b43_txhdr_size(dev), GFP_KERNEL | GFP_DMA); if (!ring->txhdr_cache) goto err_kfree_meta; dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), DMA_TO_DEVICE); - if (dma_mapping_error(dma_test)) + if (b43_dma_mapping_error(ring, dma_test, + b43_txhdr_size(dev))) goto err_kfree_txhdr_cache; } dma_unmap_single(dev->dev->dev, - dma_test, sizeof(struct b43_txhdr_fw4), + dma_test, b43_txhdr_size(dev), DMA_TO_DEVICE); } ring->dev = dev; ring->nr_slots = nr_slots; - ring->mmio_base = b43_dmacontroller_base(dma64, controller_index); + ring->mmio_base = b43_dmacontroller_base(type, controller_index); ring->index = controller_index; - ring->dma64 = !!dma64; - if (dma64) + if (type == B43_DMA_64BIT) ring->ops = &dma64_ops; else ring->ops = &dma32_ops; @@ -883,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring) if (!ring) return; - b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n", - (ring->dma64) ? "64" : "32", + b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n", + (unsigned int)(ring->type), ring->mmio_base, (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); /* Device IRQs are disabled prior entering this function, @@ -901,11 +948,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring) void b43_dma_free(struct b43_wldev *dev) { - struct b43_dma *dma; - - if (b43_using_pio(dev)) - return; - dma = &dev->dma; + struct b43_dma *dma = &dev->dma; b43_destroy_dmaring(dma->rx_ring3); dma->rx_ring3 = NULL; @@ -932,74 +975,78 @@ int b43_dma_init(struct b43_wldev *dev) struct b43_dmaring *ring; int err; u64 dmamask; - int dma64 = 0; + enum b43_dmatype type; dmamask = supported_dma_mask(dev); - if (dmamask == DMA_64BIT_MASK) - dma64 = 1; - + switch (dmamask) { + default: + B43_WARN_ON(1); + case DMA_30BIT_MASK: + type = B43_DMA_30BIT; + break; + case DMA_32BIT_MASK: + type = B43_DMA_32BIT; + break; + case DMA_64BIT_MASK: + type = B43_DMA_64BIT; + break; + } err = ssb_dma_set_mask(dev->dev, dmamask); if (err) { -#ifdef B43_PIO - b43warn(dev->wl, "DMA for this device not supported. " - "Falling back to PIO\n"); - dev->__using_pio = 1; - return -EAGAIN; -#else - b43err(dev->wl, "DMA for this device not supported and " - "no PIO support compiled in\n"); + b43err(dev->wl, "The machine/kernel does not support " + "the required DMA mask (0x%08X%08X)\n", + (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(dmamask & 0x00000000FFFFFFFFULL)); return -EOPNOTSUPP; -#endif } err = -ENOMEM; /* setup TX DMA channels. */ - ring = b43_setup_dmaring(dev, 0, 1, dma64); + ring = b43_setup_dmaring(dev, 0, 1, type); if (!ring) goto out; dma->tx_ring0 = ring; - ring = b43_setup_dmaring(dev, 1, 1, dma64); + ring = b43_setup_dmaring(dev, 1, 1, type); if (!ring) goto err_destroy_tx0; dma->tx_ring1 = ring; - ring = b43_setup_dmaring(dev, 2, 1, dma64); + ring = b43_setup_dmaring(dev, 2, 1, type); if (!ring) goto err_destroy_tx1; dma->tx_ring2 = ring; - ring = b43_setup_dmaring(dev, 3, 1, dma64); + ring = b43_setup_dmaring(dev, 3, 1, type); if (!ring) goto err_destroy_tx2; dma->tx_ring3 = ring; - ring = b43_setup_dmaring(dev, 4, 1, dma64); + ring = b43_setup_dmaring(dev, 4, 1, type); if (!ring) goto err_destroy_tx3; dma->tx_ring4 = ring; - ring = b43_setup_dmaring(dev, 5, 1, dma64); + ring = b43_setup_dmaring(dev, 5, 1, type); if (!ring) goto err_destroy_tx4; dma->tx_ring5 = ring; /* setup RX DMA channels. */ - ring = b43_setup_dmaring(dev, 0, 0, dma64); + ring = b43_setup_dmaring(dev, 0, 0, type); if (!ring) goto err_destroy_tx5; dma->rx_ring0 = ring; if (dev->dev->id.revision < 5) { - ring = b43_setup_dmaring(dev, 3, 0, dma64); + ring = b43_setup_dmaring(dev, 3, 0, type); if (!ring) goto err_destroy_rx0; dma->rx_ring3 = ring; } - b43dbg(dev->wl, "%d-bit DMA initialized\n", - (dmamask == DMA_64BIT_MASK) ? 64 : - (dmamask == DMA_32BIT_MASK) ? 32 : 30); + b43dbg(dev->wl, "%u-bit DMA initialized\n", + (unsigned int)type); err = 0; out: return err; @@ -1038,26 +1085,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot) * in the lower 12 bits. * Note that the cookie must never be 0, as this * is a special value used in RX path. + * It can also not be 0xFFFF because that is special + * for multicast frames. */ switch (ring->index) { case 0: - cookie = 0xA000; + cookie = 0x1000; break; case 1: - cookie = 0xB000; + cookie = 0x2000; break; case 2: - cookie = 0xC000; + cookie = 0x3000; break; case 3: - cookie = 0xD000; + cookie = 0x4000; break; case 4: - cookie = 0xE000; + cookie = 0x5000; break; case 5: - cookie = 0xF000; + cookie = 0x6000; break; + default: + B43_WARN_ON(1); } B43_WARN_ON(slot & ~0x0FFF); cookie |= (u16) slot; @@ -1073,22 +1124,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) struct b43_dmaring *ring = NULL; switch (cookie & 0xF000) { - case 0xA000: + case 0x1000: ring = dma->tx_ring0; break; - case 0xB000: + case 0x2000: ring = dma->tx_ring1; break; - case 0xC000: + case 0x3000: ring = dma->tx_ring2; break; - case 0xD000: + case 0x4000: ring = dma->tx_ring3; break; - case 0xE000: + case 0x5000: ring = dma->tx_ring4; break; - case 0xF000: + case 0x6000: ring = dma->tx_ring5; break; default: @@ -1106,32 +1157,45 @@ static int dma_tx_fragment(struct b43_dmaring *ring, { const struct b43_dma_ops *ops = ring->ops; u8 *header; - int slot; + int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; struct b43_dmadesc_meta *meta_hdr; struct sk_buff *bounce_skb; + u16 cookie; + size_t hdrsize = b43_txhdr_size(ring->dev); #define SLOTS_PER_PACKET 2 B43_WARN_ON(skb_shinfo(skb)->nr_frags); + old_top_slot = ring->current_slot; + old_used_slots = ring->used_slots; + /* Get a slot for the header. */ slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta_hdr); memset(meta_hdr, 0, sizeof(*meta_hdr)); - header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); - b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, - generate_cookie(ring, slot)); + header = &(ring->txhdr_cache[slot * hdrsize]); + cookie = generate_cookie(ring, slot); + err = b43_generate_txhdr(ring->dev, header, + skb->data, skb->len, ctl, cookie); + if (unlikely(err)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; + return err; + } meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, - sizeof(struct b43_txhdr_fw4), 1); - if (dma_mapping_error(meta_hdr->dmaaddr)) + hdrsize, 1); + if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; return -EIO; + } ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1, 0, 0); + hdrsize, 1, 0, 0); /* Get a slot for the payload. */ slot = request_slot(ring); @@ -1144,9 +1208,11 @@ static int dma_tx_fragment(struct b43_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ - if (dma_mapping_error(meta->dmaaddr)) { + if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } @@ -1156,7 +1222,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring, skb = bounce_skb; meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); - if (dma_mapping_error(meta->dmaaddr)) { + if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; err = -EIO; goto out_free_bounce; } @@ -1164,16 +1232,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* Tell the firmware about the cookie of the last + * mcast frame, so it can clear the more-data bit in it. */ + b43_shm_write16(ring->dev, B43_SHM_SHARED, + B43_SHM_SH_MCASTCOOKIE, cookie); + } /* Now transfer the whole frame. */ wmb(); ops->poke_tx(ring, next_slot(ring, slot)); return 0; - out_free_bounce: +out_free_bounce: dev_kfree_skb_any(skb); - out_unmap_hdr: +out_unmap_hdr: unmap_descbuffer(ring, meta_hdr->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1); + hdrsize, 1); return err; } @@ -1202,10 +1276,27 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct b43_dmaring *ring; + struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + return -EINVAL; + } + + hdr = (struct ieee80211_hdr *)skb->data; + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* The multicast ring will be sent after the DTIM */ + ring = dev->dma.tx_ring4; + /* Set the more-data bit. Ucode will clear it on + * the last frame for us. */ + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else { + /* Decide by priority where to put this frame. */ + ring = priority_to_txring(dev, ctl->queue); + } + spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { @@ -1219,6 +1310,13 @@ int b43_dma_tx(struct b43_wldev *dev, B43_WARN_ON(ring->stopped); err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err == -ENOKEY)) { + /* Drop this packet, as we don't have the encryption key + * anymore and must not transmit it unencrypted. */ + dev_kfree_skb_any(skb); + err = 0; + goto out_unlock; + } if (unlikely(err)) { b43err(dev->wl, "DMA tx mapping failure\n"); goto out_unlock; @@ -1233,7 +1331,7 @@ int b43_dma_tx(struct b43_wldev *dev, b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } } - out_unlock: +out_unlock: spin_unlock_irqrestore(&ring->lock, flags); return err; @@ -1265,7 +1363,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, 1); else unmap_descbuffer(ring, meta->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1); + b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { B43_WARN_ON(!meta->skb); diff --git a/package/b43/src/dma.h b/package/b43/src/dma.h index 3eed185be7..c0d6b69e65 100644 --- a/package/b43/src/dma.h +++ b/package/b43/src/dma.h @@ -170,8 +170,6 @@ struct b43_dmadesc_generic { #define B43_DMA0_RX_BUFFERSIZE (2304 + 100) #define B43_DMA3_RX_BUFFERSIZE 16 -#ifdef CONFIG_B43_DMA - struct sk_buff; struct b43_private; struct b43_txstatus; @@ -205,6 +203,12 @@ struct b43_dma_ops { void (*set_current_rxslot) (struct b43_dmaring * ring, int slot); }; +enum b43_dmatype { + B43_DMA_30BIT = 30, + B43_DMA_32BIT = 32, + B43_DMA_64BIT = 64, +}; + struct b43_dmaring { /* Lowlevel DMA ops. */ const struct b43_dma_ops *ops; @@ -237,8 +241,8 @@ struct b43_dmaring { int index; /* Boolean. Is this a TX ring? */ bool tx; - /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ - bool dma64; + /* The type of DMA engine used. */ + enum b43_dmatype type; /* Boolean. Is this ring stopped at ieee80211 level? */ bool stopped; /* Lock, only used for TX. */ @@ -257,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) return b43_read32(ring->dev, ring->mmio_base + offset); } -static inline - void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value) +static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value) { b43_write32(ring->dev, ring->mmio_base + offset, value); } @@ -266,13 +269,6 @@ static inline int b43_dma_init(struct b43_wldev *dev); void b43_dma_free(struct b43_wldev *dev); -int b43_dmacontroller_rx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64); -int b43_dmacontroller_tx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64); - -u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx); - void b43_dma_tx_suspend(struct b43_wldev *dev); void b43_dma_tx_resume(struct b43_wldev *dev); @@ -286,52 +282,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, void b43_dma_rx(struct b43_dmaring *ring); -#else /* CONFIG_B43_DMA */ - -static inline int b43_dma_init(struct b43_wldev *dev) -{ - return 0; -} -static inline void b43_dma_free(struct b43_wldev *dev) -{ -} -static inline - int b43_dmacontroller_rx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64) -{ - return 0; -} -static inline - int b43_dmacontroller_tx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64) -{ - return 0; -} -static inline - void b43_dma_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ -} -static inline - int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - return 0; -} -static inline - void b43_dma_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ -} -static inline void b43_dma_rx(struct b43_dmaring *ring) -{ -} -static inline void b43_dma_tx_suspend(struct b43_wldev *dev) -{ -} -static inline void b43_dma_tx_resume(struct b43_wldev *dev) -{ -} - -#endif /* CONFIG_B43_DMA */ #endif /* B43_DMA_H_ */ diff --git a/package/b43/src/leds.c b/package/b43/src/leds.c index 19e588582c..4b590d8c65 100644 --- a/package/b43/src/leds.c +++ b/package/b43/src/leds.c @@ -4,7 +4,7 @@ LED control Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -163,6 +163,9 @@ static void b43_map_led(struct b43_wldev *dev, b43_register_led(dev, &dev->led_radio, name, b43_rfkill_led_name(dev), led_index, activelow); + /* Sync the RF-kill LED state with the switch state. */ + if (dev->radio_hw_enable) + b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: case B43_LED_ASSOC: @@ -187,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev) enum b43_led_behaviour behaviour; bool activelow; - sprom[0] = bus->sprom.r1.gpio0; - sprom[1] = bus->sprom.r1.gpio1; - sprom[2] = bus->sprom.r1.gpio2; - sprom[3] = bus->sprom.r1.gpio3; + sprom[0] = bus->sprom.gpio0; + sprom[1] = bus->sprom.gpio1; + sprom[2] = bus->sprom.gpio2; + sprom[3] = bus->sprom.gpio3; for (i = 0; i < 4; i++) { if (sprom[i] == 0xFF) { @@ -232,4 +235,5 @@ void b43_leds_exit(struct b43_wldev *dev) b43_unregister_led(&dev->led_tx); b43_unregister_led(&dev->led_rx); b43_unregister_led(&dev->led_assoc); + b43_unregister_led(&dev->led_radio); } diff --git a/package/b43/src/lo.c b/package/b43/src/lo.c index b14a1753a0..d890f366a2 100644 --- a/package/b43/src/lo.c +++ b/package/b43/src/lo.c @@ -5,7 +5,7 @@ G PHY LO (LocalOscillator) Measuring and Control routines Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev, rfover |= pga; rfover |= lna; rfover |= trsw_rx; - if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) && - phy->rev > 6) + if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) + && phy->rev > 6) rfover |= B43_PHY_RFOVERVAL_EXTLNA; b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); @@ -555,20 +555,20 @@ struct lo_g_saved_values { u16 phy_extg_01; u16 phy_dacctl_hwpctl; u16 phy_dacctl; - u16 phy_base_14; + u16 phy_cck_14; u16 phy_hpwr_tssictl; u16 phy_analogover; u16 phy_analogoverval; u16 phy_rfover; u16 phy_rfoverval; u16 phy_classctl; - u16 phy_base_3E; + u16 phy_cck_3E; u16 phy_crs0; u16 phy_pgactl; - u16 phy_base_2A; + u16 phy_cck_2A; u16 phy_syncctl; - u16 phy_base_30; - u16 phy_base_06; + u16 phy_cck_30; + u16 phy_cck_06; /* Radio registers */ u16 radio_43; @@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); - sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14)); + sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, @@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_DACCTL, b43_phy_read(dev, B43_PHY_DACCTL) | 0x40); - b43_phy_write(dev, B43_PHY_BASE(0x14), - b43_phy_read(dev, B43_PHY_BASE(0x14)) + b43_phy_write(dev, B43_PHY_CCK(0x14), + b43_phy_read(dev, B43_PHY_CCK(0x14)) | 0x200); } if (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev < 6) { - b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410); - b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820); + b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); + b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); } if (!lo->rebuild && b43_has_hardware_pctl(phy)) lo_read_power_vector(dev); @@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); - sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E)); + sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); b43_phy_write(dev, B43_PHY_CLASSCTL, @@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev, & 0xFFFC); if (phy->type == B43_PHYTYPE_G) { if ((phy->rev >= 7) && - (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + (sprom->boardflags_lo & B43_BFL_EXTLNA)) { b43_phy_write(dev, B43_PHY_RFOVER, 0x933); } else { b43_phy_write(dev, B43_PHY_RFOVER, 0x133); @@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev, } else { b43_phy_write(dev, B43_PHY_RFOVER, 0); } - b43_phy_write(dev, B43_PHY_BASE(0x3E), 0); + b43_phy_write(dev, B43_PHY_CCK(0x3E), 0); } sav->reg_3F4 = b43_read16(dev, 0x3F4); sav->reg_3E2 = b43_read16(dev, 0x3E2); sav->radio_43 = b43_radio_read16(dev, 0x43); sav->radio_7A = b43_radio_read16(dev, 0x7A); sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A)); + sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A)); sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); @@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->radio_52 &= 0x00F0; } if (phy->type == B43_PHYTYPE_B) { - sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); - sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06)); - b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF); - b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F); + sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); + sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06)); + b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF); + b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F); } else { b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); @@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev, & 0xF000); tmp = - (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E); + (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E); b43_phy_write(dev, tmp, 0x007F); tmp = sav->phy_syncctl; @@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev, tmp = sav->radio_7A; b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); - b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3); + b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3); if (phy->type == B43_PHYTYPE_G || (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003); } else - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) b43_dummy_transmission(dev); b43_radio_selectchannel(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); if (lo->rebuild) lo_measure_txctl_values(dev); if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); } else { if (phy->type == B43_PHYTYPE_B) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); else b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } @@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev, } if (phy->type == B43_PHYTYPE_G) { if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); else - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); if (phy->rev >= 2) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202); else - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101); } b43_write16(dev, 0x3F4, sav->reg_3F4); b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); - b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A); + b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A); b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); b43_radio_write16(dev, 0x43, sav->radio_43); @@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_write16(dev, 0x3E2, sav->reg_3E2); if (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { - b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30); - b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06); + b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30); + b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06); } if (phy->rev >= 2) { b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); @@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); - b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E); + b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); } if (b43_has_hardware_pctl(phy)) { @@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_LO_MASK, tmp); b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); - b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14); + b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); } b43_radio_selectchannel(dev, sav->old_channel, 1); diff --git a/package/b43/src/main.c b/package/b43/src/main.c index 9f8175c25a..afb109447a 100644 --- a/package/b43/src/main.c +++ b/package/b43/src/main.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -46,7 +46,6 @@ #include "debugfs.h" #include "phy.h" #include "dma.h" -#include "pio.h" #include "sysfs.h" #include "xmit.h" #include "lo.h" @@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); -extern char *nvram_get(char *name); - -#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) -static int modparam_pio; -module_param_named(pio, modparam_pio, int, 0444); -MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); -#elif defined(CONFIG_B43_DMA) -# define modparam_pio 0 -#elif defined(CONFIG_B43_PIO) -# define modparam_pio 1 -#endif static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); -static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT; -module_param_named(short_retry, modparam_short_retry, int, 0444); -MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); - -static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; -module_param_named(long_retry, modparam_long_retry, int, 0444); -MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); @@ -101,52 +81,41 @@ static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), SSB_DEVTABLE_END }; MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); -static const struct pci_device_id b43_pci_bridge_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); - -static struct pci_driver b43_pci_bridge_driver = { - .name = "b43-pci-bridge", - .id_table = b43_pci_bridge_tbl, -}; /* Channel and ratetables are shared for all devices. * They can't be const, because ieee80211 puts some precalculated * data in there. This data is the same for all devices, so we don't * get concurrency issues */ #define RATETAB_ENT(_rateid, _flags) \ - { \ - .rate = B43_RATE_TO_BASE100KBPS(_rateid), \ - .val = (_rateid), \ - .val2 = (_rateid), \ - .flags = (_flags), \ + { \ + .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ } + +/* + * NOTE: When changing this, sync with xmit.c's + * b43_plcp_get_bitrate_idx_* functions! + */ static struct ieee80211_rate __b43_ratetable[] = { - RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK), - RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_CCK_RATE_1MB, 0), + RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_OFDM_RATE_6MB, 0), + RATETAB_ENT(B43_OFDM_RATE_9MB, 0), + RATETAB_ENT(B43_OFDM_RATE_12MB, 0), + RATETAB_ENT(B43_OFDM_RATE_18MB, 0), + RATETAB_ENT(B43_OFDM_RATE_24MB, 0), + RATETAB_ENT(B43_OFDM_RATE_36MB, 0), + RATETAB_ENT(B43_OFDM_RATE_48MB, 0), + RATETAB_ENT(B43_OFDM_RATE_54MB, 0), }; #define b43_a_ratetable (__b43_ratetable + 4) @@ -158,16 +127,10 @@ static struct ieee80211_rate __b43_ratetable[] = { #define CHANTAB_ENT(_chanid, _freq) \ { \ - .chan = (_chanid), \ - .freq = (_freq), \ - .val = (_chanid), \ - .flag = IEEE80211_CHAN_W_SCAN | \ - IEEE80211_CHAN_W_ACTIVE_SCAN | \ - IEEE80211_CHAN_W_IBSS, \ - .power_level = 0xFF, \ - .antenna_max = 0xFF, \ + .center_freq = (_freq), \ + .hw_value = (_chanid), \ } -static struct ieee80211_channel b43_bg_chantable[] = { +static struct ieee80211_channel b43_2ghz_chantable[] = { CHANTAB_ENT(1, 2412), CHANTAB_ENT(2, 2417), CHANTAB_ENT(3, 2422), @@ -184,8 +147,8 @@ static struct ieee80211_channel b43_bg_chantable[] = { CHANTAB_ENT(14, 2484), }; -#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable) -static struct ieee80211_channel b43_a_chantable[] = { +#ifdef NOTYET +static struct ieee80211_channel b43_5ghz_chantable[] = { CHANTAB_ENT(36, 5180), CHANTAB_ENT(40, 5200), CHANTAB_ENT(44, 5220), @@ -201,7 +164,20 @@ static struct ieee80211_channel b43_a_chantable[] = { CHANTAB_ENT(165, 5825), }; -#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable) +static struct ieee80211_supported_band b43_band_5GHz = { + .channels = b43_5ghz_chantable, + .n_channels = ARRAY_SIZE(b43_5ghz_chantable), + .bitrates = b43_a_ratetable, + .n_bitrates = b43_a_ratetable_size, +}; +#endif + +static struct ieee80211_supported_band b43_band_2GHz = { + .channels = b43_2ghz_chantable, + .n_channels = ARRAY_SIZE(b43_2ghz_chantable), + .bitrates = b43_g_ratetable, + .n_bitrates = b43_g_ratetable_size, +}; static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); @@ -286,13 +262,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val) b43_write32(dev, B43_MMIO_RAM_DATA, val); } -static inline - void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset) +static inline void b43_shm_control_word(struct b43_wldev *dev, + u16 routing, u16 offset) { u32 control; /* "offset" is the WORD offset. */ - control = routing; control <<= 16; control |= offset; @@ -301,8 +276,11 @@ static inline u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { + struct b43_wl *wl = dev->wl; + unsigned long flags; u32 ret; + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -313,20 +291,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, (offset >> 2) + 1); ret |= b43_read16(dev, B43_MMIO_SHM_DATA); - return ret; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); ret = b43_read32(dev, B43_MMIO_SHM_DATA); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); return ret; } u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) { + struct b43_wl *wl = dev->wl; + unsigned long flags; u16 ret; + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -334,55 +317,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset >> 2); ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); - return ret; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); ret = b43_read16(dev, B43_MMIO_SHM_DATA); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); return ret; } void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); - mmiowb(); b43_shm_control_word(dev, routing, (offset >> 2) + 1); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); - return; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); - mmiowb(); b43_write32(dev, B43_MMIO_SHM_DATA, value); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); } void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) { + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); - return; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA, value); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); } /* Read HostFlags */ @@ -1029,9 +1020,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi) static void b43_generate_noise_sample(struct b43_wldev *dev) { b43_jssi_write(dev, 0x7F7F7F7F); - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, - b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) - | (1 << 4)); + b43_write32(dev, B43_MMIO_MACCMD, + b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); } @@ -1117,18 +1107,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev) if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) b43_power_saving_ctl_bits(dev, 0); } - dev->reg124_set_0x4 = 0; if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) - dev->reg124_set_0x4 = 1; + dev->dfq_valid = 1; } static void handle_irq_atim_end(struct b43_wldev *dev) { - if (!dev->reg124_set_0x4 /*FIXME rename this variable */ ) - return; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, - b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) - | 0x4); + if (dev->dfq_valid) { + b43_write32(dev, B43_MMIO_MACCMD, + b43_read32(dev, B43_MMIO_MACCMD) + | B43_MACCMD_DFQ_VALID); + dev->dfq_valid = 0; + } } static void handle_irq_pmq(struct b43_wldev *dev) @@ -1183,29 +1173,74 @@ static void b43_write_beacon_template(struct b43_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate) { - int len; - const u8 *data; + unsigned int i, len, variable_len; + const struct ieee80211_mgmt *bcn; + const u8 *ie; + bool tim_found = 0; - B43_WARN_ON(!dev->cached_beacon); - len = min((size_t) dev->cached_beacon->len, + bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); + len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - data = (const u8 *)(dev->cached_beacon->data); - b43_write_template_common(dev, data, + + b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + + /* Find the position of the TIM and the DTIM_period value + * and write them to SHM. */ + ie = bcn->u.beacon.variable; + variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable); + for (i = 0; i < variable_len - 2; ) { + uint8_t ie_id, ie_len; + + ie_id = ie[i]; + ie_len = ie[i + 1]; + if (ie_id == 5) { + u16 tim_position; + u16 dtim_period; + /* This is the TIM Information Element */ + + /* Check whether the ie_len is in the beacon data range. */ + if (variable_len < ie_len + 2 + i) + break; + /* A valid TIM is at least 4 bytes long. */ + if (ie_len < 4) + break; + tim_found = 1; + + tim_position = sizeof(struct b43_plcp_hdr6); + tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable); + tim_position += i; + + dtim_period = ie[i + 3]; + + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_TIMBPOS, tim_position); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_DTIMPER, dtim_period); + break; + } + i += ie_len + 2; + } + if (!tim_found) { + b43warn(dev->wl, "Did not find a valid TIM IE in " + "the beacon template packet. AP or IBSS operation " + "may be broken.\n"); + } } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, - u16 shm_offset, u16 size, u8 rate) + u16 shm_offset, u16 size, + struct ieee80211_rate *rate) { struct b43_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; - b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, size, - B43_RATE_TO_BASE100KBPS(rate)); + dev->wl->vif, size, + rate); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); @@ -1219,40 +1254,44 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, * 2) Patching duration field * 3) Stripping TIM */ -static u8 *b43_generate_probe_resp(struct b43_wldev *dev, - u16 * dest_size, u8 rate) +static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, + u16 *dest_size, + struct ieee80211_rate *rate) { const u8 *src_data; u8 *dest_data; u16 src_size, elem_size, src_pos, dest_pos; __le16 dur; struct ieee80211_hdr *hdr; + size_t ie_start; + + src_size = dev->wl->current_beacon->len; + src_data = (const u8 *)dev->wl->current_beacon->data; - B43_WARN_ON(!dev->cached_beacon); - src_size = dev->cached_beacon->len; - src_data = (const u8 *)dev->cached_beacon->data; + /* Get the start offset of the variable IEs in the packet. */ + ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable)); - if (unlikely(src_size < 0x24)) { - b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n"); + if (B43_WARN_ON(src_size < ie_start)) return NULL; - } dest_data = kmalloc(src_size, GFP_ATOMIC); if (unlikely(!dest_data)) return NULL; - /* 0x24 is offset of first variable-len Information-Element - * in beacon frame. - */ - memcpy(dest_data, src_data, 0x24); - src_pos = dest_pos = 0x24; - for (; src_pos < src_size - 2; src_pos += elem_size) { + /* Copy the static data and all Information Elements, except the TIM. */ + memcpy(dest_data, src_data, ie_start); + src_pos = ie_start; + dest_pos = ie_start; + for ( ; src_pos < src_size - 2; src_pos += elem_size) { elem_size = src_data[src_pos + 1] + 2; - if (src_data[src_pos] != 0x05) { /* TIM */ - memcpy(dest_data + dest_pos, src_data + src_pos, - elem_size); - dest_pos += elem_size; + if (src_data[src_pos] == 5) { + /* This is the TIM. */ + continue; } + memcpy(dest_data + dest_pos, src_data + src_pos, + elem_size); + dest_pos += elem_size; } *dest_size = dest_pos; hdr = (struct ieee80211_hdr *)dest_data; @@ -1261,8 +1300,8 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, *dest_size, - B43_RATE_TO_BASE100KBPS(rate)); + dev->wl->vif, *dest_size, + rate); hdr->duration_id = dur; return dest_data; @@ -1270,13 +1309,13 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev, static void b43_write_probe_resp_template(struct b43_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset, + struct ieee80211_rate *rate) { - u8 *probe_resp_data; + const u8 *probe_resp_data; u16 size; - B43_WARN_ON(!dev->cached_beacon); - size = dev->cached_beacon->len; + size = dev->wl->current_beacon->len; probe_resp_data = b43_generate_probe_resp(dev, &size, rate); if (unlikely(!probe_resp_data)) return; @@ -1284,50 +1323,33 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ - b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); - b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); - b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); - b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); + b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); + b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); + b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); + b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, - size, ram_offset, shm_size_offset, rate); + size, ram_offset, shm_size_offset, + rate->hw_value); kfree(probe_resp_data); } -static int b43_refresh_cached_beacon(struct b43_wldev *dev, - struct sk_buff *beacon) -{ - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = beacon; - - return 0; -} - -static void b43_update_templates(struct b43_wldev *dev) -{ - u32 status; - - B43_WARN_ON(!dev->cached_beacon); - - b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); - b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); - b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB); - - status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); - status |= 0x03; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); -} - -static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon) +/* Asynchronously update the packet templates in template RAM. + * Locking: Requires wl->irq_lock to be locked. */ +static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) { - int err; + /* This is the top half of the ansynchronous beacon update. + * The bottom half is the beacon IRQ. + * Beacon update must be asynchronous to avoid sending an + * invalid beacon. This can happen for example, if the firmware + * transmits a beacon while we are updating it. */ - err = b43_refresh_cached_beacon(dev, beacon); - if (unlikely(err)) - return; - b43_update_templates(dev); + if (wl->current_beacon) + dev_kfree_skb_any(wl->current_beacon); + wl->current_beacon = beacon; + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; } static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) @@ -1363,33 +1385,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) static void handle_irq_beacon(struct b43_wldev *dev) { - u32 status; + struct b43_wl *wl = dev->wl; + u32 cmd; - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) return; - dev->irq_savedstate &= ~B43_IRQ_BEACON; - status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + /* This is the bottom half of the asynchronous beacon update. */ - if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { - /* ACK beacon IRQ. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); - dev->irq_savedstate |= B43_IRQ_BEACON; - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = NULL; - return; - } - if (!(status & 0x1)) { - b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); - status |= 0x1; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + cmd = b43_read32(dev, B43_MMIO_MACCMD); + if (!(cmd & B43_MACCMD_BEACON0_VALID)) { + if (!wl->beacon0_uploaded) { + b43_write_beacon_template(dev, 0x68, 0x18, + B43_CCK_RATE_1MB); + b43_write_probe_resp_template(dev, 0x268, 0x4A, + &__b43_ratetable[3]); + wl->beacon0_uploaded = 1; + } + cmd |= B43_MACCMD_BEACON0_VALID; } - if (!(status & 0x2)) { - b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); - status |= 0x2; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + if (!(cmd & B43_MACCMD_BEACON1_VALID)) { + if (!wl->beacon1_uploaded) { + b43_write_beacon_template(dev, 0x468, 0x1A, + B43_CCK_RATE_1MB); + wl->beacon1_uploaded = 1; + } + cmd |= B43_MACCMD_BEACON1_VALID; } + b43_write32(dev, B43_MMIO_MACCMD, cmd); } static void handle_irq_ucode_debug(struct b43_wldev *dev) @@ -1419,8 +1442,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (unlikely(reason & B43_IRQ_MAC_TXERR)) b43err(dev->wl, "MAC transmission error\n"); - if (unlikely(reason & B43_IRQ_PHY_TXERR)) + if (unlikely(reason & B43_IRQ_PHY_TXERR)) { b43err(dev->wl, "PHY transmission error\n"); + rmb(); + if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) { + atomic_set(&dev->phy.txerr_cnt, + B43_PHY_TX_BADNESS_LIMIT); + b43err(dev->wl, "Too many PHY TX errors, " + "restarting the controller\n"); + b43_controller_restart(dev, "PHY TX errors"); + } + } if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK | B43_DMAIRQ_NONFATALMASK))) { @@ -1462,20 +1494,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ - if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { - if (b43_using_pio(dev)) - b43_pio_rx(dev->pio.queue0); - else - b43_dma_rx(dev->dma.rx_ring0); - } + if (dma_reason[0] & B43_DMAIRQ_RX_DONE) + b43_dma_rx(dev->dma.rx_ring0); + if (dma_reason[3] & B43_DMAIRQ_RX_DONE) + b43_dma_rx(dev->dma.rx_ring3); B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); - if (dma_reason[3] & B43_DMAIRQ_RX_DONE) { - if (b43_using_pio(dev)) - b43_pio_rx(dev->pio.queue3); - else - b43_dma_rx(dev->dma.rx_ring3); - } B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); @@ -1487,29 +1511,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } -static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx) -{ - u16 rxctl; - - rxctl = b43_read16(dev, base + B43_PIO_RXCTL); - if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE) - dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE; - else - dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE; -} - static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) { - if (b43_using_pio(dev) && - (dev->dev->id.revision < 3) && - (!(reason & B43_IRQ_PIO_WORKAROUND))) { - /* Apply a PIO specific workaround to the dma_reasons */ - pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0); - pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1); - pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2); - pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3); - } - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); @@ -1568,54 +1571,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) return ret; } +static void do_release_fw(struct b43_firmware_file *fw) +{ + release_firmware(fw->data); + fw->data = NULL; + fw->filename = NULL; +} + static void b43_release_firmware(struct b43_wldev *dev) { - release_firmware(dev->fw.ucode); - dev->fw.ucode = NULL; - release_firmware(dev->fw.pcm); - dev->fw.pcm = NULL; - release_firmware(dev->fw.initvals); - dev->fw.initvals = NULL; - release_firmware(dev->fw.initvals_band); - dev->fw.initvals_band = NULL; + do_release_fw(&dev->fw.ucode); + do_release_fw(&dev->fw.pcm); + do_release_fw(&dev->fw.initvals); + do_release_fw(&dev->fw.initvals_band); } -static void b43_print_fw_helptext(struct b43_wl *wl) +static void b43_print_fw_helptext(struct b43_wl *wl, bool error) { - b43err(wl, "You must go to " - "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware " - "and download the correct firmware (version 4).\n"); + const char *text; + + text = "You must go to " + "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware " + "and download the latest firmware (version 4).\n"; + if (error) + b43err(wl, text); + else + b43warn(wl, text); } static int do_request_fw(struct b43_wldev *dev, const char *name, - const struct firmware **fw) + struct b43_firmware_file *fw) { char path[sizeof(modparam_fwpostfix) + 32]; + const struct firmware *blob; struct b43_fw_header *hdr; u32 size; int err; - if (!name) + if (!name) { + /* Don't fetch anything. Free possibly cached firmware. */ + do_release_fw(fw); return 0; + } + if (fw->filename) { + if (strcmp(fw->filename, name) == 0) + return 0; /* Already have this fw. */ + /* Free the cached firmware first. */ + do_release_fw(fw); + } snprintf(path, ARRAY_SIZE(path), "b43%s/%s.fw", modparam_fwpostfix, name); - err = request_firmware(fw, path, dev->dev->dev); + err = request_firmware(&blob, path, dev->dev->dev); if (err) { b43err(dev->wl, "Firmware file \"%s\" not found " "or load failed.\n", path); return err; } - if ((*fw)->size < sizeof(struct b43_fw_header)) + if (blob->size < sizeof(struct b43_fw_header)) goto err_format; - hdr = (struct b43_fw_header *)((*fw)->data); + hdr = (struct b43_fw_header *)(blob->data); switch (hdr->type) { case B43_FW_TYPE_UCODE: case B43_FW_TYPE_PCM: size = be32_to_cpu(hdr->size); - if (size != (*fw)->size - sizeof(struct b43_fw_header)) + if (size != blob->size - sizeof(struct b43_fw_header)) goto err_format; /* fallthrough */ case B43_FW_TYPE_IV: @@ -1626,10 +1648,15 @@ static int do_request_fw(struct b43_wldev *dev, goto err_format; } - return err; + fw->data = blob; + fw->filename = name; + + return 0; err_format: b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); + release_firmware(blob); + return -EPROTO; } @@ -1641,90 +1668,101 @@ static int b43_request_firmware(struct b43_wldev *dev) u32 tmshigh; int err; + /* Get microcode */ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); - if (!fw->ucode) { + if ((rev >= 5) && (rev <= 10)) + filename = "ucode5"; + else if ((rev >= 11) && (rev <= 12)) + filename = "ucode11"; + else if (rev >= 13) + filename = "ucode13"; + else + goto err_no_ucode; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + + /* Get PCM code */ + if ((rev >= 5) && (rev <= 10)) + filename = "pcm5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_pcm; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + + /* Get initvals */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) + filename = "a0g1initvals5"; + else + filename = "a0g0initvals5"; + } else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) - filename = "ucode5"; - else if ((rev >= 11) && (rev <= 12)) - filename = "ucode11"; + filename = "b0g0initvals5"; else if (rev >= 13) - filename = "ucode13"; + filename = "lp0initvals13"; else - goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); - if (err) - goto err_load; + goto err_no_initvals; + break; + case B43_PHYTYPE_N: + if ((rev >= 11) && (rev <= 12)) + filename = "n0initvals11"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; } - if (!fw->pcm) { + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + + /* Get bandswitch initvals */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) + filename = "a0g1bsinitvals5"; + else + filename = "a0g0bsinitvals5"; + } else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) - filename = "pcm5"; + filename = "b0g0bsinitvals5"; else if (rev >= 11) filename = NULL; else - goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) - goto err_load; - } - if (!fw->initvals) { - switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - if (tmshigh & B43_TMSHIGH_GPHY) - filename = "a0g1initvals5"; - else - filename = "a0g0initvals5"; - } else - goto err_no_initvals; - break; - case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) - filename = "b0g0initvals5"; - else if (rev >= 13) - filename = "lp0initvals13"; - else - goto err_no_initvals; - break; - default: goto err_no_initvals; - } - err = do_request_fw(dev, filename, &fw->initvals); - if (err) - goto err_load; - } - if (!fw->initvals_band) { - switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - if (tmshigh & B43_TMSHIGH_GPHY) - filename = "a0g1bsinitvals5"; - else - filename = "a0g0bsinitvals5"; - } else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; - break; - case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) - filename = "b0g0bsinitvals5"; - else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; - break; - default: + break; + case B43_PHYTYPE_N: + if ((rev >= 11) && (rev <= 12)) + filename = "n0bsinitvals11"; + else goto err_no_initvals; - } - err = do_request_fw(dev, filename, &fw->initvals_band); - if (err) - goto err_load; + break; + default: + goto err_no_initvals; } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; return 0; err_load: - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); goto error; err_no_ucode: @@ -1754,22 +1792,33 @@ static int b43_upload_microcode(struct b43_wldev *dev) const __be32 *data; unsigned int i, len; u16 fwrev, fwpatch, fwdate, fwtime; - u32 tmp; + u32 tmp, macctl; int err = 0; + /* Jump the microcode PSM to offset 0 */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN); + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Zero out all microcode PSM registers and shared memory. */ + for (i = 0; i < 64; i++) + b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0); + for (i = 0; i < 4096; i += 2) + b43_shm_write16(dev, B43_SHM_SHARED, i, 0); + /* Upload Microcode. */ - data = (__be32 *) (dev->fw.ucode->data + hdr_len); - len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + data = (__be32 *) (dev->fw.ucode.data->data + hdr_len); + len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); for (i = 0; i < len; i++) { b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } - if (dev->fw.pcm) { + if (dev->fw.pcm.data) { /* Upload PCM data. */ - data = (__be32 *) (dev->fw.pcm->data + hdr_len); - len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + data = (__be32 *) (dev->fw.pcm.data->data + hdr_len); + len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); /* No need for autoinc bit in SHM_HW */ @@ -1781,9 +1830,12 @@ static int b43_upload_microcode(struct b43_wldev *dev) } b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); - b43_write32(dev, B43_MMIO_MACCTL, - B43_MACCTL_PSM_RUN | - B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA); + + /* Start the microcode PSM */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_JMP0; + macctl |= B43_MACCTL_PSM_RUN; + b43_write32(dev, B43_MMIO_MACCTL, macctl); /* Wait for the microcode to load and respond */ i = 0; @@ -1792,13 +1844,17 @@ static int b43_upload_microcode(struct b43_wldev *dev) if (tmp == B43_IRQ_MAC_SUSPENDED) break; i++; - if (i >= 50) { + if (i >= 20) { b43err(dev->wl, "Microcode not responding\n"); - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); err = -ENODEV; - goto out; + goto error; + } + msleep_interruptible(50); + if (signal_pending(current)) { + err = -EINTR; + goto error; } - udelay(10); } b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ @@ -1812,10 +1868,9 @@ static int b43_upload_microcode(struct b43_wldev *dev) b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " "binary drivers older than version 4.x is unsupported. " "You must upgrade your firmware files.\n"); - b43_print_fw_helptext(dev->wl); - b43_write32(dev, B43_MMIO_MACCTL, 0); + b43_print_fw_helptext(dev->wl, 1); err = -EOPNOTSUPP; - goto out; + goto error; } b43dbg(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -1826,7 +1881,20 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.rev = fwrev; dev->fw.patch = fwpatch; - out: + if (b43_is_old_txhdr_format(dev)) { + b43warn(dev->wl, "You are using an old firmware image. " + "Support for old firmware will be removed in July 2008.\n"); + b43_print_fw_helptext(dev->wl, 0); + } + + return 0; + +error: + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_RUN; + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + return err; } @@ -1886,7 +1954,7 @@ static int b43_write_initvals(struct b43_wldev *dev, err_format: b43err(dev->wl, "Initial Values Firmware file-format error.\n"); - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); return -EPROTO; } @@ -1900,19 +1968,19 @@ static int b43_upload_initvals(struct b43_wldev *dev) size_t count; int err; - hdr = (const struct b43_fw_header *)(fw->initvals->data); - ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); + hdr = (const struct b43_fw_header *)(fw->initvals.data->data); + ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, - fw->initvals->size - hdr_len); + fw->initvals.data->size - hdr_len); if (err) goto out; - if (fw->initvals_band) { - hdr = (const struct b43_fw_header *)(fw->initvals_band->data); - ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); + if (fw->initvals_band.data) { + hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data); + ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, - fw->initvals_band->size - hdr_len); + fw->initvals_band.data->size - hdr_len); if (err) goto out; } @@ -1949,7 +2017,7 @@ static int b43_gpio_init(struct b43_wldev *dev) mask |= 0x0180; set |= 0x0180; } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) { b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x0200); @@ -2119,6 +2187,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) switch (dev->phy.type) { case B43_PHYTYPE_A: case B43_PHYTYPE_G: + case B43_PHYTYPE_N: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -2148,13 +2217,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) switch (antenna) { case B43_ANTENNA0: - ant |= B43_TX4_PHY_ANT0; + ant |= B43_TXH_PHY_ANT0; break; case B43_ANTENNA1: - ant |= B43_TX4_PHY_ANT1; + ant |= B43_TXH_PHY_ANT1; + break; + case B43_ANTENNA2: + ant |= B43_TXH_PHY_ANT2; + break; + case B43_ANTENNA3: + ant |= B43_TXH_PHY_ANT3; break; case B43_ANTENNA_AUTO: - ant |= B43_TX4_PHY_ANTLAST; + ant |= B43_TXH_PHY_ANT01AUTO; break; default: B43_WARN_ON(1); @@ -2164,15 +2239,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* For Beacons */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); /* For ACK/CTS */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp); /* For Probe Resposes */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } @@ -2180,7 +2255,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev, 1); - b43_leds_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ } @@ -2192,11 +2266,15 @@ static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err, tmp; - u32 value32; + u32 value32, macctl; u16 value16; - b43_write32(dev, B43_MMIO_MACCTL, - B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED); + /* Initialize the MAC control */ + macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED; + if (dev->phy.gmode) + macctl |= B43_MACCTL_GMODE; + macctl |= B43_MACCTL_INFRA; + b43_write32(dev, B43_MMIO_MACCTL, macctl); err = b43_request_firmware(dev); if (err) @@ -2208,11 +2286,10 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_gpio_init(dev); if (err) goto out; /* firmware is released later */ - b43_leds_init(dev); err = b43_upload_initvals(dev); if (err) - goto err_leds_exit; + goto err_gpio_clean; b43_radio_turn_on(dev); b43_write16(dev, 0x03E6, 0x0000); @@ -2242,14 +2319,6 @@ static int b43_chip_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | B43_MACCTL_INFRA); - if (b43_using_pio(dev)) { - b43_write32(dev, 0x0210, 0x00000100); - b43_write32(dev, 0x0230, 0x00000100); - b43_write32(dev, 0x0250, 0x00000100); - b43_write32(dev, 0x0270, 0x00000100); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000); - } - /* Probe Response Timeout value */ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000); @@ -2288,8 +2357,7 @@ out: err_radio_off: b43_radio_turn_off(dev, 1); -err_leds_exit: - b43_leds_exit(dev); +err_gpio_clean: b43_gpio_cleanup(dev); return err; } @@ -2312,9 +2380,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + if (phy->type != B43_PHYTYPE_G) + return; if (!b43_has_hardware_pctl(phy)) b43_lo_g_ctl_mark_all_unused(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_mac_suspend(dev); b43_calc_nrssi_slope(dev); if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { @@ -2366,6 +2436,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } b43_phy_xmitpower(dev); //FIXME: unless scanning? //TODO for APHY (temperature?) + + atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); + wmb(); } static void do_periodic_work(struct b43_wldev *dev) @@ -2423,32 +2496,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) queue_delayed_work(dev->wl->hw->workqueue, work, 0); } -/* Validate access to the chip (SHM) */ +/* Check if communication with the device works correctly. */ static int b43_validate_chipaccess(struct b43_wldev *dev) { - u32 value; - u32 shm_backup; + u32 v, backup; - shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); - b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); - if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) - goto error; + backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + + /* Check for read/write and endianness problems. */ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55) goto error; - b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup); - - value = b43_read32(dev, B43_MMIO_MACCTL); - if ((value | B43_MACCTL_GMODE) != - (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) goto error; - value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); - if (value) + b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); + + if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { + /* The 32bit register shadows the two 16bit registers + * with update sideeffects. Validate this. */ + b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA); + b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB); + if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB) + goto error; + if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC) + goto error; + } + b43_write32(dev, B43_MMIO_TSF_CFP_START, 0); + + v = b43_read32(dev, B43_MMIO_MACCTL); + v |= B43_MACCTL_GMODE; + if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) goto error; return 0; - error: +error: b43err(dev->wl, "Failed to validate the chipaccess\n"); return -ENODEV; } @@ -2511,40 +2594,35 @@ static int b43_rng_init(struct b43_wl *wl) return err; } -static int b43_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +static int b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; int err = -ENODEV; - unsigned long flags; if (unlikely(!dev)) goto out; if (unlikely(b43_status(dev) < B43_STAT_STARTED)) goto out; /* DMA-TX is done without a global lock. */ - if (b43_using_pio(dev)) { - spin_lock_irqsave(&wl->irq_lock, flags); - err = b43_pio_tx(dev, skb, ctl); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } else - err = b43_dma_tx(dev, skb, ctl); - out: + err = b43_dma_tx(dev, skb, ctl); +out: if (unlikely(err)) return NETDEV_TX_BUSY; return NETDEV_TX_OK; } -static int b43_conf_tx(struct ieee80211_hw *hw, - int queue, - const struct ieee80211_tx_queue_params *params) +static int b43_op_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) { return 0; } -static int b43_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +static int b43_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2555,19 +2633,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw, goto out; spin_lock_irqsave(&wl->irq_lock, flags); if (likely(b43_status(dev) >= B43_STAT_STARTED)) { - if (b43_using_pio(dev)) - b43_pio_get_tx_stats(dev, stats); - else - b43_dma_get_tx_stats(dev, stats); + b43_dma_get_tx_stats(dev, stats); err = 0; } spin_unlock_irqrestore(&wl->irq_lock, flags); - out: +out: return err; } -static int b43_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int b43_op_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; @@ -2706,8 +2781,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) return err; } -static int b43_antenna_from_ieee80211(u8 antenna) +/* Check if the use of the antenna that ieee80211 told us to + * use is possible. This will fall back to DEFAULT. + * "antenna_nr" is the antenna identifier we got from ieee80211. */ +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, + u8 antenna_nr) { + u8 antenna_mask; + + if (antenna_nr == 0) { + /* Zero means "use default antenna". That's always OK. */ + return 0; + } + + /* Get the mask of available antennas. */ + if (dev->phy.gmode) + antenna_mask = dev->dev->bus->sprom.ant_available_bg; + else + antenna_mask = dev->dev->bus->sprom.ant_available_a; + + if (!(antenna_mask & (1 << (antenna_nr - 1)))) { + /* This antenna is not available. Fall back to default. */ + return 0; + } + + return antenna_nr; +} + +static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) +{ + antenna = b43_ieee80211_antenna_sanitize(dev, antenna); switch (antenna) { case 0: /* default/diversity */ return B43_ANTENNA_DEFAULT; @@ -2715,37 +2818,34 @@ static int b43_antenna_from_ieee80211(u8 antenna) return B43_ANTENNA0; case 2: /* Antenna 1 */ return B43_ANTENNA1; + case 3: /* Antenna 2 */ + return B43_ANTENNA2; + case 4: /* Antenna 3 */ + return B43_ANTENNA3; default: return B43_ANTENNA_DEFAULT; } } -static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; unsigned long flags; unsigned int new_phymode = 0xFFFF; - int antenna_tx; - int antenna_rx; + int antenna; int err = 0; u32 savedirqs; - antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx); - mutex_lock(&wl->mutex); /* Switch the PHY mode (if necessary). */ - switch (conf->phymode) { - case MODE_IEEE80211A: + switch (conf->channel->band) { + case IEEE80211_BAND_5GHZ: new_phymode = B43_PHYMODE_A; break; - case MODE_IEEE80211B: - new_phymode = B43_PHYMODE_B; - break; - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: new_phymode = B43_PHYMODE_G; break; default: @@ -2771,8 +2871,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - if (conf->channel_val != phy->channel) - b43_radio_selectchannel(dev, conf->channel_val, 0); + if (conf->channel->hw_value != phy->channel) + b43_radio_selectchannel(dev, conf->channel->hw_value, 0); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -2784,6 +2884,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) b43_short_slot_timing_disable(dev); } + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + /* Adjust the desired TX power level. */ if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { @@ -2793,8 +2895,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - b43_mgmtframe_txantenna(dev, antenna_tx); - b43_set_rx_antenna(dev, antenna_rx); + antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + b43_mgmtframe_txantenna(dev, antenna); + antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + b43_set_rx_antenna(dev, antenna); /* Update templates for AP mode. */ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) @@ -2825,22 +2929,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return err; } -static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; + struct b43_wldev *dev; unsigned long flags; u8 algorithm; u8 index; - int err = -EINVAL; + int err; + DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ - if (!dev) - return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + dev = wl->current_dev; + err = -ENODEV; + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + err = -EINVAL; switch (key->alg) { case ALG_WEP: if (key->keylen == 5) @@ -2856,20 +2968,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; default: B43_WARN_ON(1); - goto out; + goto out_unlock; } - index = (u8) (key->keyidx); if (index > 3) - goto out; - - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - - if (b43_status(dev) < B43_STAT_INITIALIZED) { - err = -ENODEV; goto out_unlock; - } switch (cmd) { case SET_KEY: @@ -2915,19 +3018,18 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, out_unlock: spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); -out: if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: " MAC_FMT "\n", + "mac: %s\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - MAC_ARG(addr)); + print_mac(mac, addr)); } return err; } -static void b43_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, unsigned int *fflags, - int mc_count, struct dev_addr_list *mc_list) +static void b43_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, unsigned int *fflags, + int mc_count, struct dev_addr_list *mc_list) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2962,8 +3064,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43_config_interface(struct ieee80211_hw *hw, - int if_id, struct ieee80211_if_conf *conf) +static int b43_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2973,7 +3076,7 @@ static int b43_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - B43_WARN_ON(wl->if_id != if_id); + B43_WARN_ON(wl->vif != vif); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else @@ -2983,7 +3086,7 @@ static int b43_config_interface(struct ieee80211_hw *hw, B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->beacon) - b43_refresh_templates(dev, conf->beacon); + b43_update_templates(wl, conf->beacon); } b43_write_mac_bssid_templates(dev); } @@ -3001,6 +3104,16 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) if (b43_status(dev) < B43_STAT_STARTED) return; + + /* Disable and sync interrupts. We must do this before than + * setting the status to INITIALIZED, as the interrupt handler + * won't care about IRQs then. */ + spin_lock_irqsave(&wl->irq_lock, flags); + dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + b43_set_status(dev, B43_STAT_INITIALIZED); mutex_unlock(&wl->mutex); @@ -3011,13 +3124,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy. - /* Disable and sync interrupts. */ - spin_lock_irqsave(&wl->irq_lock, flags); - dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); - b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); - b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); @@ -3083,9 +3189,15 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_G: - if (phy_rev > 8) + if (phy_rev > 9) + unsupported = 1; + break; +#ifdef CONFIG_B43_NPHY + case B43_PHYTYPE_N: + if (phy_rev > 1) unsupported = 1; break; +#endif default: unsupported = 1; }; @@ -3108,14 +3220,15 @@ static int b43_phy_versioning(struct b43_wldev *dev) tmp = 0x5205017F; } else { b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH); - tmp <<= 16; + tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); + tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16; } radio_manuf = (tmp & 0x00000FFF); radio_ver = (tmp & 0x0FFFF000) >> 12; radio_rev = (tmp & 0xF0000000) >> 28; + if (radio_manuf != 0x17F /* Broadcom */) + unsupported = 1; switch (phy_type) { case B43_PHYTYPE_A: if (radio_ver != 0x2060) @@ -3133,6 +3246,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_ver != 0x2050) unsupported = 1; break; + case B43_PHYTYPE_N: + if (radio_ver != 0x2055) + unsupported = 1; + break; default: B43_WARN_ON(1); } @@ -3165,9 +3282,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - /* Flags */ - phy->locked = 0; - phy->aci_enable = 0; phy->aci_wlan_automatic = 0; phy->aci_hw_rssi = 0; @@ -3194,17 +3308,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - spin_lock_init(&phy->lock); phy->interfmode = B43_INTERFMODE_NONE; phy->channel = 0xFF; phy->hardware_power_control = !!modparam_hwpctl; + + /* PHY TX errors counter. */ + atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); + + /* OFDM-table address caching. */ + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; } static void setup_struct_wldev_for_init(struct b43_wldev *dev) { - /* Flags */ - dev->reg124_set_0x4 = 0; + dev->dfq_valid = 0; + /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ dev->radio_hw_enable = 1; @@ -3230,13 +3349,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev) struct ssb_sprom *sprom = &dev->dev->bus->sprom; u32 hf; - if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST)) + if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST)) return; if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode) return; hf = b43_hf_read(dev); - if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD) + if (sprom->boardflags_lo & B43_BFL_BTCMOD) hf |= B43_HF_BTCOEXALT; else hf |= B43_HF_BTCOEX; @@ -3275,23 +3394,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } +/* Write the short and long frame retry limit values. */ +static void b43_set_retry_limits(struct b43_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, + short_retry); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + long_retry); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + u32 macctl; B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); if (b43_status(dev) != B43_STAT_INITIALIZED) return; b43_set_status(dev, B43_STAT_UNINIT); - mutex_unlock(&dev->wl->mutex); - b43_rfkill_exit(dev); - mutex_lock(&dev->wl->mutex); + /* Stop the microcode PSM. */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_RUN; + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + b43_leds_exit(dev); b43_rng_exit(dev->wl); - b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); b43_radio_turn_off(dev, 1); @@ -3300,6 +3438,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) kfree(phy->tssi2dbm); kfree(phy->lo_control); phy->lo_control = NULL; + if (dev->wl->current_beacon) { + dev_kfree_skb_any(dev->wl->current_beacon); + dev->wl->current_beacon = NULL; + } + ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); } @@ -3354,7 +3497,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) hf |= B43_HF_SYMW; if (phy->rev == 1) hf |= B43_HF_GDCW; - if (sprom->r1.boardflags_lo & B43_BFL_PACTRL) + if (sprom->boardflags_lo & B43_BFL_PACTRL) hf |= B43_HF_OFDMPABOOST; } else if (phy->type == B43_PHYTYPE_B) { hf |= B43_HF_SYMW; @@ -3363,15 +3506,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) } b43_hf_write(dev, hf); - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - tmp = limit_value(modparam_short_retry, 0, 0xF); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp); - tmp = limit_value(modparam_long_retry, 0, 0xF); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp); - + b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, + B43_DEFAULT_LONG_RETRY_LIMIT); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2); @@ -3392,17 +3528,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - do { - if (b43_using_pio(dev)) { - err = b43_pio_init(dev); - } else { - err = b43_dma_init(dev); - if (!err) - b43_qos_init(dev); - } - } while (err == -EAGAIN); + err = b43_dma_init(dev); if (err) goto err_chip_exit; + b43_qos_init(dev); //FIXME #if 1 @@ -3414,16 +3543,14 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_bluetooth_coext_enable(dev); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - memset(wl->bssid, 0, ETH_ALEN); - memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); - b43_rfkill_init(dev); b43_rng_init(wl); b43_set_status(dev, B43_STAT_INITIALIZED); - out: + b43_leds_init(dev); +out: return err; err_chip_exit: @@ -3440,8 +3567,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) return err; } -static int b43_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static int b43_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3464,7 +3591,7 @@ static int b43_add_interface(struct ieee80211_hw *hw, dev = wl->current_dev; wl->operating = 1; - wl->if_id = conf->if_id; + wl->vif = conf->vif; wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); @@ -3480,8 +3607,8 @@ static int b43_add_interface(struct ieee80211_hw *hw, return err; } -static void b43_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static void b43_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3492,7 +3619,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); B43_WARN_ON(!wl->operating); - B43_WARN_ON(wl->if_id != conf->if_id); + B43_WARN_ON(wl->vif != conf->vif); + wl->vif = NULL; wl->operating = 0; @@ -3505,19 +3633,34 @@ static void b43_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int b43_start(struct ieee80211_hw *hw) +static int b43_op_start(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; + bool do_rfkill_exit = 0; + + /* Kill all old instance specific information to make sure + * the card won't use it in the short timeframe between start + * and mac80211 reconfiguring it. */ + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->mac_addr, 0, ETH_ALEN); + wl->filter_flags = 0; + wl->radiotap_enabled = 0; + + /* First register RFkill. + * LEDs that are registered later depend on it. */ + b43_rfkill_init(dev); mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); - if (err) + if (err) { + do_rfkill_exit = 1; goto out_mutex_unlock; + } did_init = 1; } @@ -3526,6 +3669,7 @@ static int b43_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43_wireless_core_exit(dev); + do_rfkill_exit = 1; goto out_mutex_unlock; } } @@ -3533,14 +3677,19 @@ static int b43_start(struct ieee80211_hw *hw) out_mutex_unlock: mutex_unlock(&wl->mutex); + if (do_rfkill_exit) + b43_rfkill_exit(dev); + return err; } -static void b43_stop(struct ieee80211_hw *hw) +static void b43_op_stop(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; + b43_rfkill_exit(dev); + mutex_lock(&wl->mutex); if (b43_status(dev) >= B43_STAT_STARTED) b43_wireless_core_stop(dev); @@ -3548,19 +3697,76 @@ static void b43_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } +static int b43_op_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry_limit, u32 long_retry_limit) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int err = 0; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) { + err = -ENODEV; + goto out_unlock; + } + b43_set_retry_limits(dev, short_retry_limit, long_retry_limit); +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct sk_buff *beacon; + unsigned long flags; + + /* We could modify the existing beacon and set the aid bit in + * the TIM field, but that would probably require resizing and + * moving of data within the beacon template. + * Simply request a new beacon and let mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + if (unlikely(!beacon)) + return -ENOMEM; + spin_lock_irqsave(&wl->irq_lock, flags); + b43_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *beacon, + struct ieee80211_tx_control *ctl) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + static const struct ieee80211_ops b43_hw_ops = { - .tx = b43_tx, - .conf_tx = b43_conf_tx, - .add_interface = b43_add_interface, - .remove_interface = b43_remove_interface, - .config = b43_dev_config, - .config_interface = b43_config_interface, - .configure_filter = b43_configure_filter, - .set_key = b43_dev_set_key, - .get_stats = b43_get_stats, - .get_tx_stats = b43_get_tx_stats, - .start = b43_start, - .stop = b43_stop, + .tx = b43_op_tx, + .conf_tx = b43_op_conf_tx, + .add_interface = b43_op_add_interface, + .remove_interface = b43_op_remove_interface, + .config = b43_op_config, + .config_interface = b43_op_config_interface, + .configure_filter = b43_op_configure_filter, + .set_key = b43_op_set_key, + .get_stats = b43_op_get_stats, + .get_tx_stats = b43_op_get_tx_stats, + .start = b43_op_start, + .stop = b43_op_stop, + .set_retry_limit = b43_op_set_retry_limit, + .set_tim = b43_op_beacon_set_tim, + .beacon_update = b43_op_ibss_beacon_update, }; /* Hard-reset the chip. Do not call this directly. @@ -3605,79 +3811,26 @@ static void b43_chip_reset(struct work_struct *work) } static int b43_setup_modes(struct b43_wldev *dev, - int have_aphy, int have_bphy, int have_gphy) + bool have_2ghz_phy, bool have_5ghz_phy) { struct ieee80211_hw *hw = dev->wl->hw; - struct ieee80211_hw_mode *mode; struct b43_phy *phy = &dev->phy; - int cnt = 0; - int err; -/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */ - have_aphy = 0; - - phy->possible_phymodes = 0; - for (; 1; cnt++) { - if (have_aphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211A; - mode->num_channels = b43_a_chantable_size; - mode->channels = b43_a_chantable; - mode->num_rates = b43_a_ratetable_size; - mode->rates = b43_a_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_A; - have_aphy = 0; - continue; - } - if (have_bphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211B; - mode->num_channels = b43_bg_chantable_size; - mode->channels = b43_bg_chantable; - mode->num_rates = b43_b_ratetable_size; - mode->rates = b43_b_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_B; - have_bphy = 0; - continue; - } - if (have_gphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43_bg_chantable_size; - mode->channels = b43_bg_chantable; - mode->num_rates = b43_g_ratetable_size; - mode->rates = b43_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_G; - have_gphy = 0; - continue; - } - break; - } + /* XXX: This function will go away soon, when mac80211 + * band stuff is rewritten. So this is just a hack. + * For now we always claim GPHY mode, as there is no + * support for NPHY and APHY in the device, yet. + * This assumption is OK, as any B, N or A PHY will already + * have died a horrible sanity check death earlier. */ + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; + phy->possible_phymodes |= B43_PHYMODE_G; return 0; } static void b43_wireless_core_detach(struct b43_wldev *dev) { - b43_rfkill_free(dev); /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43_release_firmware(dev); @@ -3689,7 +3842,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) struct ssb_bus *bus = dev->dev->bus; struct pci_dev *pdev = bus->host_pci; int err; - int have_aphy = 0, have_bphy = 0, have_gphy = 0; + bool have_2ghz_phy = 0, have_5ghz_phy = 0; u32 tmp; /* Do NOT do any device initialization here. @@ -3709,17 +3862,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) u32 tmshigh; tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); - have_aphy = !!(tmshigh & B43_TMSHIGH_APHY); - have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY); - if (!have_aphy && !have_gphy) - have_bphy = 1; - } else if (dev->dev->id.revision == 4) { - have_gphy = 1; - have_aphy = 1; + have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY); + have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY); } else - have_bphy = 1; + B43_WARN_ON(1); - dev->phy.gmode = (have_gphy || have_bphy); + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); @@ -3731,31 +3879,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) (pdev->device != 0x4312 && pdev->device != 0x4319 && pdev->device != 0x4324)) { /* No multiband support. */ - have_aphy = 0; - have_bphy = 0; - have_gphy = 0; + have_2ghz_phy = 0; + have_5ghz_phy = 0; switch (dev->phy.type) { case B43_PHYTYPE_A: - have_aphy = 1; - break; - case B43_PHYTYPE_B: - have_bphy = 1; + have_5ghz_phy = 1; break; case B43_PHYTYPE_G: - have_gphy = 1; + case B43_PHYTYPE_N: + have_2ghz_phy = 1; break; default: B43_WARN_ON(1); } } - dev->phy.gmode = (have_gphy || have_bphy); + if (dev->phy.type == B43_PHYTYPE_A) { + /* FIXME */ + b43err(wl, "IEEE 802.11a devices are unsupported\n"); + err = -EOPNOTSUPP; + goto err_powerdown; + } + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_validate_chipaccess(dev); if (err) goto err_powerdown; - err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); + err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy); if (err) goto err_powerdown; @@ -3763,7 +3914,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_rfkill_alloc(dev); b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); @@ -3827,8 +3977,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) tasklet_init(&wldev->isr_tasklet, (void (*)(unsigned long))b43_interrupt_tasklet, (unsigned long)wldev); - if (modparam_pio) - wldev->__using_pio = 1; INIT_LIST_HEAD(&wldev->list); err = b43_wireless_core_attach(wldev); @@ -3853,20 +4001,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) - bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST; + bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST; if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) - bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL; - - /* Handle case when gain is not set in sprom */ - if (bus->sprom.r1.antenna_gain_a == 0xFF) - bus->sprom.r1.antenna_gain_a = 2; - if (bus->sprom.r1.antenna_gain_bg == 0xFF) - bus->sprom.r1.antenna_gain_bg = 2; - - /* Convert Antennagain values to Q5.2 */ - bus->sprom.r1.antenna_gain_a <<= 2; - bus->sprom.r1.antenna_gain_bg <<= 2; + bus->sprom.boardflags_lo |= B43_BFL_PACTRL; } static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) @@ -3893,16 +4031,17 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); - if (is_valid_ether_addr(sprom->r1.et1mac)) - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + if (is_valid_ether_addr(sprom->et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); else - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); /* Get and initialize struct b43_wl */ wl = hw_to_b43_wl(hw); @@ -3910,6 +4049,7 @@ static int b43_wireless_init(struct ssb_device *dev) wl->hw = hw; spin_lock_init(&wl->irq_lock); spin_lock_init(&wl->leds_lock); + spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); @@ -4053,16 +4193,6 @@ static struct ssb_driver b43_ssb_driver = { .resume = b43_resume, }; -inline int b43_pci_ssb_bridge_init(void) -{ - return ssb_pcihost_register(&b43_pci_bridge_driver); -} - -inline void b43_pci_ssb_bridge_exit(void) -{ - ssb_pcihost_unregister(&b43_pci_bridge_driver); -} - static int __init b43_init(void) { int err; @@ -4071,19 +4201,12 @@ static int __init b43_init(void) err = b43_pcmcia_init(); if (err) goto err_dfs_exit; - - err = b43_pci_ssb_bridge_init(); - if (err) - goto err_pcmcia_exit; - err = ssb_driver_register(&b43_ssb_driver); if (err) - goto err_pci_exit; + goto err_pcmcia_exit; return err; -err_pci_exit: - b43_pci_ssb_bridge_exit(); err_pcmcia_exit: b43_pcmcia_exit(); err_dfs_exit: @@ -4094,7 +4217,6 @@ err_dfs_exit: static void __exit b43_exit(void) { ssb_driver_unregister(&b43_ssb_driver); - b43_pci_ssb_bridge_exit(); b43_pcmcia_exit(); b43_debugfs_exit(); } diff --git a/package/b43/src/main.h b/package/b43/src/main.h index 284d17da17..2d52d9de93 100644 --- a/package/b43/src/main.h +++ b/package/b43/src/main.h @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mb@bu3sch.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -39,11 +39,11 @@ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ -static inline u8 b43_freq_to_channel_a(int freq) +static inline u8 b43_freq_to_channel_5ghz(int freq) { return ((freq - 5000) / 5); } -static inline u8 b43_freq_to_channel_bg(int freq) +static inline u8 b43_freq_to_channel_2ghz(int freq) { u8 channel; @@ -54,19 +54,13 @@ static inline u8 b43_freq_to_channel_bg(int freq) return channel; } -static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq) -{ - if (dev->phy.type == B43_PHYTYPE_A) - return b43_freq_to_channel_a(freq); - return b43_freq_to_channel_bg(freq); -} /* Lightweight function to convert a channel number to a frequency (in Mhz). */ -static inline int b43_channel_to_freq_a(u8 channel) +static inline int b43_channel_to_freq_5ghz(u8 channel) { return (5000 + (5 * channel)); } -static inline int b43_channel_to_freq_bg(u8 channel) +static inline int b43_channel_to_freq_2ghz(u8 channel) { int freq; @@ -77,12 +71,6 @@ static inline int b43_channel_to_freq_bg(u8 channel) return freq; } -static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel) -{ - if (dev->phy.type == B43_PHYTYPE_A) - return b43_channel_to_freq_a(channel); - return b43_channel_to_freq_bg(channel); -} static inline int b43_is_cck_rate(int rate) { @@ -96,6 +84,9 @@ static inline int b43_is_ofdm_rate(int rate) return !b43_is_cck_rate(rate); } +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, + u8 antenna_nr); + void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); diff --git a/package/b43/src/nphy.c b/package/b43/src/nphy.c new file mode 100644 index 0000000000..705131ef4b --- /dev/null +++ b/package/b43/src/nphy.c @@ -0,0 +1,489 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY support + + Copyright (c) 2008 Michael Buesch <mb@bu3sch.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include <linux/delay.h> +#include <linux/types.h> + +#include "b43.h" +#include "nphy.h" +#include "tables_nphy.h" + +#include <linux/delay.h> + + +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) +{//TODO +} + +void b43_nphy_xmitpower(struct b43_wldev *dev) +{//TODO +} + +static void b43_chantab_radio_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref); + b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0); + b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1); + b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail); + b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1); + b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2); + b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1); + b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1); + b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2); + b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf); + b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1); + b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2); + b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune); + b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune); + b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1); + b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn); + b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim); + b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune); + b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune); + b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1); + b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn); + b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); +} + +static void b43_chantab_phy_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a); + b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2); + b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3); + b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4); + b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5); + b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); +} + +static void b43_nphy_tx_power_fix(struct b43_wldev *dev) +{ + //TODO +} + +/* Tune the hardware to a new channel. Don't call this directly. + * Use b43_radio_selectchannel() */ +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +{ + const struct b43_nphy_channeltab_entry *tabent; + + tabent = b43_nphy_get_chantabent(dev, channel); + if (!tabent) + return -ESRCH; + + //FIXME enable/disable band select upper20 in RXCTL + if (0 /*FIXME 5Ghz*/) + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20); + else + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50); + b43_chantab_radio_upload(dev, tabent); + udelay(50); + b43_radio_write16(dev, B2055_VCO_CAL10, 5); + b43_radio_write16(dev, B2055_VCO_CAL10, 45); + b43_radio_write16(dev, B2055_VCO_CAL10, 65); + udelay(300); + if (0 /*FIXME 5Ghz*/) + b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); + else + b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); + b43_chantab_phy_upload(dev, tabent); + b43_nphy_tx_power_fix(dev); + + return 0; +} + +static void b43_radio_init2055_pre(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_PORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_CHIP0PU | + B43_NPHY_RFCTL_CMD_OEPORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_PORFORCE); +} + +static void b43_radio_init2055_post(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo); + int i; + u16 val; + + b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); + msleep(1); + if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { + if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || + (binfo->type != 0x46D) || + (binfo->rev < 0x41)) { + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + msleep(1); + } + } + b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C); + msleep(1); + b43_radio_write16(dev, B2055_CAL_MISC, 0x3C); + msleep(1); + b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE); + msleep(1); + b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x1); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x40); + msleep(1); + for (i = 0; i < 100; i++) { + val = b43_radio_read16(dev, B2055_CAL_COUT2); + if (val & 0x80) + break; + udelay(10); + } + msleep(1); + b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); + msleep(1); + b43_radio_selectchannel(dev, dev->phy.channel, 0); + b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); + b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83); +} + +/* Initialize a Broadcom 2055 N-radio */ +static void b43_radio_init2055(struct b43_wldev *dev) +{ + b43_radio_init2055_pre(dev); + if (b43_status(dev) < B43_STAT_INITIALIZED) + b2055_upload_inittab(dev, 0, 1); + else + b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0); + b43_radio_init2055_post(dev); +} + +void b43_nphy_radio_turn_on(struct b43_wldev *dev) +{ + b43_radio_init2055(dev); +} + +void b43_nphy_radio_turn_off(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_EN); +} + +#define ntab_upload(dev, offset, data) do { \ + unsigned int i; \ + for (i = 0; i < (offset##_SIZE); i++) \ + b43_ntab_write(dev, (offset) + i, (data)[i]); \ + } while (0) + +/* Upload the N-PHY tables. */ +static void b43_nphy_tables_init(struct b43_wldev *dev) +{ + /* Static tables */ + ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); + ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); + ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); + ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); + ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); + ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); + ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); + ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); + ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); + ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); + ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); + ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); + ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); + ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); + + /* Volatile tables */ + ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); + ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); + ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); + ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); + ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); + ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); + ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); + ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); + ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); + ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); +} + +static void b43_nphy_workarounds(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + unsigned int i; + + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + //FIXME the following condition is different in the specs. + if (1 /* FIXME band is 2.4GHz */) { + b43_phy_set(dev, B43_NPHY_CLASSCTL, + B43_NPHY_CLASSCTL_CCKEN); + } else { + b43_phy_mask(dev, B43_NPHY_CLASSCTL, + ~B43_NPHY_CLASSCTL_CCKEN); + } + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); + + /* Fixup some tables */ + b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); + b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); + + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + + //TODO set RF sequence + + /* Set narrowband clip threshold */ + b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); + b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); + + /* Set wideband clip 2 threshold */ + b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, + ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, + ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); + + /* Set Clip 2 detect */ + b43_phy_set(dev, B43_NPHY_C1_CGAINI, + B43_NPHY_C1_CGAINI_CL2DETECT); + b43_phy_set(dev, B43_NPHY_C2_CGAINI, + B43_NPHY_C2_CGAINI_CL2DETECT); + + if (0 /*FIXME*/) { + /* Set dwell lengths */ + b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); + b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); + + /* Set gain backoff */ + b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, + ~B43_NPHY_C1_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, + ~B43_NPHY_C2_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); + + /* Set HPVGA2 index */ + b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, + ~B43_NPHY_C1_INITGAIN_HPVGA2, + 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, + ~B43_NPHY_C2_INITGAIN_HPVGA2, + 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); + + //FIXME verify that the specs really mean to use autoinc here. + for (i = 0; i < 3; i++) + b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); + } + + /* Set minimum gain value */ + b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, + ~B43_NPHY_C1_MINGAIN, + 23 << B43_NPHY_C1_MINGAIN_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, + ~B43_NPHY_C2_MINGAIN, + 23 << B43_NPHY_C2_MINGAIN_SHIFT); + + if (phy->rev < 2) { + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + } + + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); +} + +static void b43_nphy_reset_cca(struct b43_wldev *dev) +{ + u16 bbcfg; + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); + bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); + b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); + b43_phy_write(dev, B43_NPHY_BBCFG, + bbcfg & ~B43_NPHY_BBCFG_RSTCCA); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); +} + +enum b43_nphy_rf_sequence { + B43_RFSEQ_RX2TX, + B43_RFSEQ_TX2RX, + B43_RFSEQ_RESET2RX, + B43_RFSEQ_UPDATE_GAINH, + B43_RFSEQ_UPDATE_GAINL, + B43_RFSEQ_UPDATE_GAINU, +}; + +static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, + enum b43_nphy_rf_sequence seq) +{ + static const u16 trigger[] = { + [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, + [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, + [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, + [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, + [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, + [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, + }; + int i; + + B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); + + b43_phy_set(dev, B43_NPHY_RFSEQMODE, + B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); + b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) + goto ok; + msleep(1); + } + b43err(dev->wl, "RF sequence status timeout\n"); +ok: + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); +} + +static void b43_nphy_bphy_init(struct b43_wldev *dev) +{ + unsigned int i; + u16 val; + + val = 0x1E1F; + for (i = 0; i < 14; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; + } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); + val -= 0x202; + } + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); +} + +/* RSSI Calibration */ +static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) +{ + //TODO +} + +int b43_phy_initn(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + //TODO: Spectral management + b43_nphy_tables_init(dev); + + /* Clear all overrides */ + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | + B43_NPHY_RFSEQMODE_TROVER)); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); + + tmp = (phy->rev < 2) ? 64 : 59; + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, + ~B43_NPHY_BPHY_CTL3_SCALE, + tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); + + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); + + b43_phy_write(dev, B43_NPHY_TXREALFD, 184); + b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); + b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); + + //TODO MIMO-Config + //TODO Update TX/RX chain + + if (phy->rev < 2) { + b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); + b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); + } + b43_nphy_workarounds(dev); + b43_nphy_reset_cca(dev); + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + + b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ + //TODO read core1/2 clip1 thres regs + + if (1 /* FIXME Band is 2.4GHz */) + b43_nphy_bphy_init(dev); + //TODO disable TX power control + //TODO Fix the TX power settings + //TODO Init periodic calibration with reason 3 + b43_nphy_rssi_cal(dev, 2); + b43_nphy_rssi_cal(dev, 0); + b43_nphy_rssi_cal(dev, 1); + //TODO get TX gain + //TODO init superswitch + //TODO calibrate LO + //TODO idle TSSI TX pctl + //TODO TX power control power setup + //TODO table writes + //TODO TX power control coefficients + //TODO enable TX power control + //TODO control antenna selection + //TODO init radar detection + //TODO reset channel if changed + + b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); + return 0; +} diff --git a/package/b43/src/nphy.h b/package/b43/src/nphy.h new file mode 100644 index 0000000000..5d95118b81 --- /dev/null +++ b/package/b43/src/nphy.h @@ -0,0 +1,932 @@ +#ifndef B43_NPHY_H_ +#define B43_NPHY_H_ + +#include "phy.h" + + +/* N-PHY registers. */ + +#define B43_NPHY_BBCFG B43_PHY_N(0x001) /* BB config */ +#define B43_NPHY_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_NPHY_BBCFG_RSTRX 0x8000 /* Reset RX */ +#define B43_NPHY_CHANNEL B43_PHY_N(0x005) /* Channel */ +#define B43_NPHY_TXERR B43_PHY_N(0x007) /* TX error */ +#define B43_NPHY_BANDCTL B43_PHY_N(0x009) /* Band control */ +#define B43_NPHY_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */ +#define B43_NPHY_4WI_ADDR B43_PHY_N(0x00B) /* Four-wire bus address */ +#define B43_NPHY_4WI_DATAHI B43_PHY_N(0x00C) /* Four-wire bus data high */ +#define B43_NPHY_4WI_DATALO B43_PHY_N(0x00D) /* Four-wire bus data low */ +#define B43_NPHY_BIST_STAT0 B43_PHY_N(0x00E) /* Built-in self test status 0 */ +#define B43_NPHY_BIST_STAT1 B43_PHY_N(0x00F) /* Built-in self test status 1 */ + +#define B43_NPHY_C1_DESPWR B43_PHY_N(0x018) /* Core 1 desired power */ +#define B43_NPHY_C1_CCK_DESPWR B43_PHY_N(0x019) /* Core 1 CCK desired power */ +#define B43_NPHY_C1_BCLIPBKOFF B43_PHY_N(0x01A) /* Core 1 barely clip backoff */ +#define B43_NPHY_C1_CCK_BCLIPBKOFF B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */ +#define B43_NPHY_C1_CGAINI B43_PHY_N(0x01C) /* Core 1 compute gain info */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C1_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C1_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C1_CCK_CGAINI B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */ +#define B43_NPHY_C1_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C1_MINMAX_GAIN B43_PHY_N(0x01E) /* Core 1 min/max gain */ +#define B43_NPHY_C1_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_CCK_MINMAX_GAIN B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */ +#define B43_NPHY_C1_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_INITGAIN B43_PHY_N(0x020) /* Core 1 initial gain code */ +#define B43_NPHY_C1_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C1_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C1_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C1_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C1_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C1_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C1_CLIP1_HIGAIN B43_PHY_N(0x021) /* Core 1 clip1 high gain code */ +#define B43_NPHY_C1_CLIP1_MEDGAIN B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */ +#define B43_NPHY_C1_CLIP1_LOGAIN B43_PHY_N(0x023) /* Core 1 clip1 low gain code */ +#define B43_NPHY_C1_CLIP2_GAIN B43_PHY_N(0x024) /* Core 1 clip2 gain code */ +#define B43_NPHY_C1_FILTERGAIN B43_PHY_N(0x025) /* Core 1 filter gain */ +#define B43_NPHY_C1_LPF_QHPF_BW B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */ +#define B43_NPHY_C1_CLIPWBTHRES B43_PHY_N(0x027) /* Core 1 clip wideband threshold */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C1_W1THRES B43_PHY_N(0x028) /* Core 1 W1 threshold */ +#define B43_NPHY_C1_EDTHRES B43_PHY_N(0x029) /* Core 1 ED threshold */ +#define B43_NPHY_C1_SMSIGTHRES B43_PHY_N(0x02A) /* Core 1 small sig threshold */ +#define B43_NPHY_C1_NBCLIPTHRES B43_PHY_N(0x02B) /* Core 1 NB clip threshold */ +#define B43_NPHY_C1_CLIP1THRES B43_PHY_N(0x02C) /* Core 1 clip1 threshold */ +#define B43_NPHY_C1_CLIP2THRES B43_PHY_N(0x02D) /* Core 1 clip2 threshold */ + +#define B43_NPHY_C2_DESPWR B43_PHY_N(0x02E) /* Core 2 desired power */ +#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x02F) /* Core 2 CCK desired power */ +#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x030) /* Core 2 barely clip backoff */ +#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */ +#define B43_NPHY_C2_CGAINI B43_PHY_N(0x032) /* Core 2 compute gain info */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C2_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C2_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x033) /* Core 2 CCK compute gain info */ +#define B43_NPHY_C2_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x034) /* Core 2 min/max gain */ +#define B43_NPHY_C2_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x035) /* Core 2 CCK min/max gain */ +#define B43_NPHY_C2_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x036) /* Core 2 initial gain code */ +#define B43_NPHY_C2_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C2_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C2_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C2_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */ +#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */ +#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */ +#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */ +#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */ +#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */ +#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C2_W1THRES B43_PHY_N(0x03E) /* Core 2 W1 threshold */ +#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x03F) /* Core 2 ED threshold */ +#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x040) /* Core 2 small sig threshold */ +#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x041) /* Core 2 NB clip threshold */ +#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x042) /* Core 2 clip1 threshold */ +#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x043) /* Core 2 clip2 threshold */ + +#define B43_NPHY_CRS_THRES1 B43_PHY_N(0x044) /* CRS threshold 1 */ +#define B43_NPHY_CRS_THRES2 B43_PHY_N(0x045) /* CRS threshold 2 */ +#define B43_NPHY_CRS_THRES3 B43_PHY_N(0x046) /* CRS threshold 3 */ +#define B43_NPHY_CRSCTL B43_PHY_N(0x047) /* CRS control */ +#define B43_NPHY_DCFADDR B43_PHY_N(0x048) /* DC filter address */ +#define B43_NPHY_RXF20_NUM0 B43_PHY_N(0x049) /* RX filter 20 numerator 0 */ +#define B43_NPHY_RXF20_NUM1 B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */ +#define B43_NPHY_RXF20_NUM2 B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */ +#define B43_NPHY_RXF20_DENOM0 B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */ +#define B43_NPHY_RXF20_DENOM1 B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */ +#define B43_NPHY_RXF20_NUM10 B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */ +#define B43_NPHY_RXF20_NUM11 B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */ +#define B43_NPHY_RXF20_NUM12 B43_PHY_N(0x050) /* RX filter 20 numerator 12 */ +#define B43_NPHY_RXF20_DENOM10 B43_PHY_N(0x051) /* RX filter 20 denominator 10 */ +#define B43_NPHY_RXF20_DENOM11 B43_PHY_N(0x052) /* RX filter 20 denominator 11 */ +#define B43_NPHY_RXF40_NUM0 B43_PHY_N(0x053) /* RX filter 40 numerator 0 */ +#define B43_NPHY_RXF40_NUM1 B43_PHY_N(0x054) /* RX filter 40 numerator 1 */ +#define B43_NPHY_RXF40_NUM2 B43_PHY_N(0x055) /* RX filter 40 numerator 2 */ +#define B43_NPHY_RXF40_DENOM0 B43_PHY_N(0x056) /* RX filter 40 denominator 0 */ +#define B43_NPHY_RXF40_DENOM1 B43_PHY_N(0x057) /* RX filter 40 denominator 1 */ +#define B43_NPHY_RXF40_NUM10 B43_PHY_N(0x058) /* RX filter 40 numerator 10 */ +#define B43_NPHY_RXF40_NUM11 B43_PHY_N(0x059) /* RX filter 40 numerator 11 */ +#define B43_NPHY_RXF40_NUM12 B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */ +#define B43_NPHY_RXF40_DENOM10 B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */ +#define B43_NPHY_RXF40_DENOM11 B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */ +#define B43_NPHY_PPROC_RSTLEN B43_PHY_N(0x060) /* Packet processing reset length */ +#define B43_NPHY_INITCARR_DLEN B43_PHY_N(0x061) /* Initial carrier detection length */ +#define B43_NPHY_CLIP1CARR_DLEN B43_PHY_N(0x062) /* Clip1 carrier detection length */ +#define B43_NPHY_CLIP2CARR_DLEN B43_PHY_N(0x063) /* Clip2 carrier detection length */ +#define B43_NPHY_INITGAIN_SLEN B43_PHY_N(0x064) /* Initial gain settle length */ +#define B43_NPHY_CLIP1GAIN_SLEN B43_PHY_N(0x065) /* Clip1 gain settle length */ +#define B43_NPHY_CLIP2GAIN_SLEN B43_PHY_N(0x066) /* Clip2 gain settle length */ +#define B43_NPHY_PACKGAIN_SLEN B43_PHY_N(0x067) /* Packet gain settle length */ +#define B43_NPHY_CARRSRC_TLEN B43_PHY_N(0x068) /* Carrier search timeout length */ +#define B43_NPHY_TISRC_TLEN B43_PHY_N(0x069) /* Timing search timeout length */ +#define B43_NPHY_ENDROP_TLEN B43_PHY_N(0x06A) /* Energy drop timeout length */ +#define B43_NPHY_CLIP1_NBDWELL_LEN B43_PHY_N(0x06B) /* Clip1 NB dwell length */ +#define B43_NPHY_CLIP2_NBDWELL_LEN B43_PHY_N(0x06C) /* Clip2 NB dwell length */ +#define B43_NPHY_W1CLIP1_DWELL_LEN B43_PHY_N(0x06D) /* W1 clip1 dwell length */ +#define B43_NPHY_W1CLIP2_DWELL_LEN B43_PHY_N(0x06E) /* W1 clip2 dwell length */ +#define B43_NPHY_W2CLIP1_DWELL_LEN B43_PHY_N(0x06F) /* W2 clip1 dwell length */ +#define B43_NPHY_PLOAD_CSENSE_EXTLEN B43_PHY_N(0x070) /* Payload carrier sense extension length */ +#define B43_NPHY_EDROP_CSENSE_EXTLEN B43_PHY_N(0x071) /* Energy drop carrier sense extension length */ +#define B43_NPHY_TABLE_ADDR B43_PHY_N(0x072) /* Table address */ +#define B43_NPHY_TABLE_DATALO B43_PHY_N(0x073) /* Table data low */ +#define B43_NPHY_TABLE_DATAHI B43_PHY_N(0x074) /* Table data high */ +#define B43_NPHY_WWISE_LENIDX B43_PHY_N(0x075) /* WWiSE length index */ +#define B43_NPHY_TGNSYNC_LENIDX B43_PHY_N(0x076) /* TGNsync length index */ +#define B43_NPHY_TXMACIF_HOLDOFF B43_PHY_N(0x077) /* TX MAC IF Hold off */ +#define B43_NPHY_RFCTL_CMD B43_PHY_N(0x078) /* RF control (command) */ +#define B43_NPHY_RFCTL_CMD_START 0x0001 /* Start sequence */ +#define B43_NPHY_RFCTL_CMD_RXTX 0x0002 /* RX/TX */ +#define B43_NPHY_RFCTL_CMD_CORESEL 0x0038 /* Core select */ +#define B43_NPHY_RFCTL_CMD_CORESEL_SHIFT 3 +#define B43_NPHY_RFCTL_CMD_PORFORCE 0x0040 /* POR force */ +#define B43_NPHY_RFCTL_CMD_OEPORFORCE 0x0080 /* OE POR force */ +#define B43_NPHY_RFCTL_CMD_RXEN 0x0100 /* RX enable */ +#define B43_NPHY_RFCTL_CMD_TXEN 0x0200 /* TX enable */ +#define B43_NPHY_RFCTL_CMD_CHIP0PU 0x0400 /* Chip0 PU */ +#define B43_NPHY_RFCTL_CMD_EN 0x0800 /* Radio enabled */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE 0xF000 /* Seq en core */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT 12 +#define B43_NPHY_RFCTL_RSSIO1 B43_PHY_N(0x07A) /* RF control (RSSI others 1) */ +#define B43_NPHY_RFCTL_RSSIO1_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO1_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO1_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO1_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO1_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO1_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO1_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG1 B43_PHY_N(0x07B) /* RF control (RX gain 1) */ +#define B43_NPHY_RFCTL_TXG1 B43_PHY_N(0x07C) /* RF control (TX gain 1) */ +#define B43_NPHY_RFCTL_RSSIO2 B43_PHY_N(0x07D) /* RF control (RSSI others 2) */ +#define B43_NPHY_RFCTL_RSSIO2_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO2_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO2_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO2_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO2_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO2_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO2_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG2 B43_PHY_N(0x07E) /* RF control (RX gain 2) */ +#define B43_NPHY_RFCTL_TXG2 B43_PHY_N(0x07F) /* RF control (TX gain 2) */ +#define B43_NPHY_RFCTL_RSSIO3 B43_PHY_N(0x080) /* RF control (RSSI others 3) */ +#define B43_NPHY_RFCTL_RSSIO3_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO3_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO3_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO3_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO3_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO3_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO3_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG3 B43_PHY_N(0x081) /* RF control (RX gain 3) */ +#define B43_NPHY_RFCTL_TXG3 B43_PHY_N(0x082) /* RF control (TX gain 3) */ +#define B43_NPHY_RFCTL_RSSIO4 B43_PHY_N(0x083) /* RF control (RSSI others 4) */ +#define B43_NPHY_RFCTL_RSSIO4_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO4_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO4_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO4_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO4_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO4_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO4_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG4 B43_PHY_N(0x084) /* RF control (RX gain 4) */ +#define B43_NPHY_RFCTL_TXG4 B43_PHY_N(0x085) /* RF control (TX gain 4) */ +#define B43_NPHY_C1_TXIQ_COMP_OFF B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */ +#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ +#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ +#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ +#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ +#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ +#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 +#define B43_NPHY_SCRAM_SIGCTL_SCM 0x0080 /* Scram control mode */ +#define B43_NPHY_SCRAM_SIGCTL_SICE 0x0100 /* Scram index control enable */ +#define B43_NPHY_SCRAM_SIGCTL_START 0xFE00 /* Scram start bit */ +#define B43_NPHY_SCRAM_SIGCTL_START_SHIFT 9 +#define B43_NPHY_RFCTL_INTC1 B43_PHY_N(0x091) /* RF control (intc 1) */ +#define B43_NPHY_RFCTL_INTC2 B43_PHY_N(0x092) /* RF control (intc 2) */ +#define B43_NPHY_RFCTL_INTC3 B43_PHY_N(0x093) /* RF control (intc 3) */ +#define B43_NPHY_RFCTL_INTC4 B43_PHY_N(0x094) /* RF control (intc 4) */ +#define B43_NPHY_NRDTO_WWISE B43_PHY_N(0x095) /* # datatones WWiSE */ +#define B43_NPHY_NRDTO_TGNSYNC B43_PHY_N(0x096) /* # datatones TGNsync */ +#define B43_NPHY_SIGFMOD_WWISE B43_PHY_N(0x097) /* Signal field mod WWiSE */ +#define B43_NPHY_LEG_SIGFMOD_11N B43_PHY_N(0x098) /* Legacy signal field mod 11n */ +#define B43_NPHY_HT_SIGFMOD_11N B43_PHY_N(0x099) /* HT signal field mod 11n */ +#define B43_NPHY_C1_RXIQ_COMPA0 B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */ +#define B43_NPHY_C1_RXIQ_COMPB0 B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */ +#define B43_NPHY_C2_RXIQ_COMPA1 B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */ +#define B43_NPHY_C2_RXIQ_COMPB1 B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */ +#define B43_NPHY_RXCTL B43_PHY_N(0x0A0) /* RX control */ +#define B43_NPHY_RXCTL_BSELU20 0x0010 /* Band select upper 20 */ +#define B43_NPHY_RXCTL_RIFSEN 0x0080 /* RIFS enable */ +#define B43_NPHY_RFSEQMODE B43_PHY_N(0x0A1) /* RF seq mode */ +#define B43_NPHY_RFSEQMODE_CAOVER 0x0001 /* Core active override */ +#define B43_NPHY_RFSEQMODE_TROVER 0x0002 /* Trigger override */ +#define B43_NPHY_RFSEQCA B43_PHY_N(0x0A2) /* RF seq core active */ +#define B43_NPHY_RFSEQCA_TXEN 0x000F /* TX enable */ +#define B43_NPHY_RFSEQCA_TXEN_SHIFT 0 +#define B43_NPHY_RFSEQCA_RXEN 0x00F0 /* RX enable */ +#define B43_NPHY_RFSEQCA_RXEN_SHIFT 4 +#define B43_NPHY_RFSEQCA_TXDIS 0x0F00 /* TX disable */ +#define B43_NPHY_RFSEQCA_TXDIS_SHIFT 8 +#define B43_NPHY_RFSEQCA_RXDIS 0xF000 /* RX disable */ +#define B43_NPHY_RFSEQCA_RXDIS_SHIFT 12 +#define B43_NPHY_RFSEQTR B43_PHY_N(0x0A3) /* RF seq trigger */ +#define B43_NPHY_RFSEQTR_RX2TX 0x0001 /* RX2TX */ +#define B43_NPHY_RFSEQTR_TX2RX 0x0002 /* TX2RX */ +#define B43_NPHY_RFSEQTR_UPGH 0x0004 /* Update gain H */ +#define B43_NPHY_RFSEQTR_UPGL 0x0008 /* Update gain L */ +#define B43_NPHY_RFSEQTR_UPGU 0x0010 /* Update gain U */ +#define B43_NPHY_RFSEQTR_RST2RX 0x0020 /* Reset to RX */ +#define B43_NPHY_RFSEQST B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */ +#define B43_NPHY_AFECTL_OVER B43_PHY_N(0x0A5) /* AFE control override */ +#define B43_NPHY_AFECTL_C1 B43_PHY_N(0x0A6) /* AFE control core 1 */ +#define B43_NPHY_AFECTL_C2 B43_PHY_N(0x0A7) /* AFE control core 2 */ +#define B43_NPHY_AFECTL_C3 B43_PHY_N(0x0A8) /* AFE control core 3 */ +#define B43_NPHY_AFECTL_C4 B43_PHY_N(0x0A9) /* AFE control core 4 */ +#define B43_NPHY_AFECTL_DACGAIN1 B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */ +#define B43_NPHY_AFECTL_DACGAIN2 B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */ +#define B43_NPHY_AFECTL_DACGAIN3 B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */ +#define B43_NPHY_AFECTL_DACGAIN4 B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */ +#define B43_NPHY_STR_ADDR1 B43_PHY_N(0x0AE) /* STR address 1 */ +#define B43_NPHY_STR_ADDR2 B43_PHY_N(0x0AF) /* STR address 2 */ +#define B43_NPHY_CLASSCTL B43_PHY_N(0x0B0) /* Classifier control */ +#define B43_NPHY_CLASSCTL_CCKEN 0x0001 /* CCK enable */ +#define B43_NPHY_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ +#define B43_NPHY_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ +#define B43_NPHY_IQFLIP B43_PHY_N(0x0B1) /* I/Q flip */ +#define B43_NPHY_IQFLIP_ADC1 0x0001 /* ADC1 */ +#define B43_NPHY_IQFLIP_ADC2 0x0010 /* ADC2 */ +#define B43_NPHY_SISO_SNR_THRES B43_PHY_N(0x0B2) /* SISO SNR threshold */ +#define B43_NPHY_SIGMA_N_MULT B43_PHY_N(0x0B3) /* Sigma N multiplier */ +#define B43_NPHY_TXMACDELAY B43_PHY_N(0x0B4) /* TX MAC delay */ +#define B43_NPHY_TXFRAMEDELAY B43_PHY_N(0x0B5) /* TX frame delay */ +#define B43_NPHY_MLPARM B43_PHY_N(0x0B6) /* ML parameters */ +#define B43_NPHY_MLCTL B43_PHY_N(0x0B7) /* ML control */ +#define B43_NPHY_WWISE_20NCYCDAT B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */ +#define B43_NPHY_WWISE_40NCYCDAT B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */ +#define B43_NPHY_TGNSYNC_20NCYCDAT B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */ +#define B43_NPHY_TGNSYNC_40NCYCDAT B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */ +#define B43_NPHY_INITSWIZP B43_PHY_N(0x0BC) /* Initial swizzle pattern */ +#define B43_NPHY_TXTAILCNT B43_PHY_N(0x0BD) /* TX tail count value */ +#define B43_NPHY_BPHY_CTL1 B43_PHY_N(0x0BE) /* B PHY control 1 */ +#define B43_NPHY_BPHY_CTL2 B43_PHY_N(0x0BF) /* B PHY control 2 */ +#define B43_NPHY_BPHY_CTL2_LUT 0x001F /* LUT index */ +#define B43_NPHY_BPHY_CTL2_LUT_SHIFT 0 +#define B43_NPHY_BPHY_CTL2_MACDEL 0x7FE0 /* MAC delay */ +#define B43_NPHY_BPHY_CTL2_MACDEL_SHIFT 5 +#define B43_NPHY_IQLOCAL_CMD B43_PHY_N(0x0C0) /* I/Q LO cal command */ +#define B43_NPHY_IQLOCAL_CMD_EN 0x8000 +#define B43_NPHY_IQLOCAL_CMDNNUM B43_PHY_N(0x0C1) /* I/Q LO cal command N num */ +#define B43_NPHY_IQLOCAL_CMDGCTL B43_PHY_N(0x0C2) /* I/Q LO cal command G control */ +#define B43_NPHY_SAMP_CMD B43_PHY_N(0x0C3) /* Sample command */ +#define B43_NPHY_SAMP_CMD_STOP 0x0002 /* Stop */ +#define B43_NPHY_SAMP_LOOPCNT B43_PHY_N(0x0C4) /* Sample loop count */ +#define B43_NPHY_SAMP_WAITCNT B43_PHY_N(0x0C5) /* Sample wait count */ +#define B43_NPHY_SAMP_DEPCNT B43_PHY_N(0x0C6) /* Sample depth count */ +#define B43_NPHY_SAMP_STAT B43_PHY_N(0x0C7) /* Sample status */ +#define B43_NPHY_GPIO_LOOEN B43_PHY_N(0x0C8) /* GPIO low out enable */ +#define B43_NPHY_GPIO_HIOEN B43_PHY_N(0x0C9) /* GPIO high out enable */ +#define B43_NPHY_GPIO_SEL B43_PHY_N(0x0CA) /* GPIO select */ +#define B43_NPHY_GPIO_CLKCTL B43_PHY_N(0x0CB) /* GPIO clock control */ +#define B43_NPHY_TXF_20CO_AS0 B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */ +#define B43_NPHY_TXF_20CO_AS1 B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */ +#define B43_NPHY_TXF_20CO_AS2 B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */ +#define B43_NPHY_TXF_20CO_B32S0 B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */ +#define B43_NPHY_TXF_20CO_B1S0 B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */ +#define B43_NPHY_TXF_20CO_B32S1 B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */ +#define B43_NPHY_TXF_20CO_B1S1 B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */ +#define B43_NPHY_TXF_20CO_B32S2 B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */ +#define B43_NPHY_TXF_20CO_B1S2 B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */ +#define B43_NPHY_SIGFLDTOL B43_PHY_N(0x0D5) /* Signal fld tolerance */ +#define B43_NPHY_TXSERFLD B43_PHY_N(0x0D6) /* TX service field */ +#define B43_NPHY_AFESEQ_RX2TX_PUD B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */ +#define B43_NPHY_AFESEQ_TX2RX_PUD B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */ +#define B43_NPHY_TGNSYNC_SCRAMI0 B43_PHY_N(0x0D9) /* TGNsync scram init 0 */ +#define B43_NPHY_TGNSYNC_SCRAMI1 B43_PHY_N(0x0DA) /* TGNsync scram init 1 */ +#define B43_NPHY_INITSWIZPATTLEG B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */ +#define B43_NPHY_BPHY_CTL3 B43_PHY_N(0x0DC) /* B PHY control 3 */ +#define B43_NPHY_BPHY_CTL3_SCALE 0x00FF /* Scale */ +#define B43_NPHY_BPHY_CTL3_SCALE_SHIFT 0 +#define B43_NPHY_BPHY_CTL3_FSC 0xFF00 /* Frame start count value */ +#define B43_NPHY_BPHY_CTL3_FSC_SHIFT 8 +#define B43_NPHY_BPHY_CTL4 B43_PHY_N(0x0DD) /* B PHY control 4 */ +#define B43_NPHY_C1_TXBBMULT B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */ +#define B43_NPHY_C2_TXBBMULT B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */ +#define B43_NPHY_TXF_40CO_AS0 B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */ +#define B43_NPHY_TXF_40CO_AS1 B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */ +#define B43_NPHY_TXF_40CO_AS2 B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */ +#define B43_NPHY_TXF_40CO_B32S0 B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */ +#define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */ +#define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */ +#define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */ +#define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */ +#define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */ +#define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */ +#define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */ +#define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */ +#define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */ +#define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */ +#define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */ +#define B43_NPHY_RADAR_BLNKCTL B43_PHY_N(0x0EE) /* Radar blank control */ +#define B43_NPHY_A0RADAR_FIFOCTL B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */ +#define B43_NPHY_A1RADAR_FIFOCTL B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */ +#define B43_NPHY_A0RADAR_FIFODAT B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */ +#define B43_NPHY_A1RADAR_FIFODAT B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */ +#define B43_NPHY_RADAR_THRES0 B43_PHY_N(0x0F3) /* Radar threshold 0 */ +#define B43_NPHY_RADAR_THRES1 B43_PHY_N(0x0F4) /* Radar threshold 1 */ +#define B43_NPHY_RADAR_THRES0R B43_PHY_N(0x0F5) /* Radar threshold 0R */ +#define B43_NPHY_RADAR_THRES1R B43_PHY_N(0x0F6) /* Radar threshold 1R */ +#define B43_NPHY_CSEN_20IN40_DLEN B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO1 B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP1 B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO2 B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP2 B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO3 B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP3 B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO4 B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP4 B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */ +#define B43_NPHY_RFCTL_LUT_LNAPA1 B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */ +#define B43_NPHY_RFCTL_LUT_LNAPA2 B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */ +#define B43_NPHY_RFCTL_LUT_LNAPA3 B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */ +#define B43_NPHY_RFCTL_LUT_LNAPA4 B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */ +#define B43_NPHY_TGNSYNC_CRCM0 B43_PHY_N(0x104) /* TGNsync CRC mask 0 */ +#define B43_NPHY_TGNSYNC_CRCM1 B43_PHY_N(0x105) /* TGNsync CRC mask 1 */ +#define B43_NPHY_TGNSYNC_CRCM2 B43_PHY_N(0x106) /* TGNsync CRC mask 2 */ +#define B43_NPHY_TGNSYNC_CRCM3 B43_PHY_N(0x107) /* TGNsync CRC mask 3 */ +#define B43_NPHY_TGNSYNC_CRCM4 B43_PHY_N(0x108) /* TGNsync CRC mask 4 */ +#define B43_NPHY_CRCPOLY B43_PHY_N(0x109) /* CRC polynomial */ +#define B43_NPHY_SIGCNT B43_PHY_N(0x10A) /* # sig count */ +#define B43_NPHY_SIGSTARTBIT_CTL B43_PHY_N(0x10B) /* Sig start bit control */ +#define B43_NPHY_CRCPOLY_ORDER B43_PHY_N(0x10C) /* CRC polynomial order */ +#define B43_NPHY_RFCTL_CST0 B43_PHY_N(0x10D) /* RF control core swap table 0 */ +#define B43_NPHY_RFCTL_CST1 B43_PHY_N(0x10E) /* RF control core swap table 1 */ +#define B43_NPHY_RFCTL_CST2O B43_PHY_N(0x10F) /* RF control core swap table 2 + others */ +#define B43_NPHY_BPHY_CTL5 B43_PHY_N(0x111) /* B PHY control 5 */ +#define B43_NPHY_RFSEQ_LPFBW B43_PHY_N(0x112) /* RF seq LPF bandwidth */ +#define B43_NPHY_TSSIBIAS1 B43_PHY_N(0x114) /* TSSI bias val 1 */ +#define B43_NPHY_TSSIBIAS2 B43_PHY_N(0x115) /* TSSI bias val 2 */ +#define B43_NPHY_TSSIBIAS_BIAS 0x00FF /* Bias */ +#define B43_NPHY_TSSIBIAS_BIAS_SHIFT 0 +#define B43_NPHY_TSSIBIAS_VAL 0xFF00 /* Value */ +#define B43_NPHY_TSSIBIAS_VAL_SHIFT 8 +#define B43_NPHY_ESTPWR1 B43_PHY_N(0x118) /* Estimated power 1 */ +#define B43_NPHY_ESTPWR2 B43_PHY_N(0x119) /* Estimated power 2 */ +#define B43_NPHY_ESTPWR_PWR 0x00FF /* Estimated power */ +#define B43_NPHY_ESTPWR_PWR_SHIFT 0 +#define B43_NPHY_ESTPWR_VALID 0x0100 /* Estimated power valid */ +#define B43_NPHY_TSSI_MAXTXFDT B43_PHY_N(0x11C) /* TSSI max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL 0x00FF /* max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT 0 +#define B43_NPHY_TSSI_MAXTDT B43_PHY_N(0x11D) /* TSSI max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL 0x00FF /* max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL_SHIFT 0 +#define B43_NPHY_ITSSI1 B43_PHY_N(0x11E) /* TSSI idle 1 */ +#define B43_NPHY_ITSSI2 B43_PHY_N(0x11F) /* TSSI idle 2 */ +#define B43_NPHY_ITSSI_VAL 0x00FF /* Idle TSSI */ +#define B43_NPHY_ITSSI_VAL_SHIFT 0 +#define B43_NPHY_TSSIMODE B43_PHY_N(0x122) /* TSSI mode */ +#define B43_NPHY_TSSIMODE_EN 0x0001 /* TSSI enable */ +#define B43_NPHY_TSSIMODE_PDEN 0x0002 /* Power det enable */ +#define B43_NPHY_RXMACIFM B43_PHY_N(0x123) /* RX Macif mode */ +#define B43_NPHY_CRSIT_COCNT_LO B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */ +#define B43_NPHY_CRSIT_COCNT_HI B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */ +#define B43_NPHY_CRSIT_MTCNT_LO B43_PHY_N(0x126) /* CRS idle time measure time count (low) */ +#define B43_NPHY_CRSIT_MTCNT_HI B43_PHY_N(0x127) /* CRS idle time measure time count (high) */ +#define B43_NPHY_SAMTWC B43_PHY_N(0x128) /* Sample tail wait count */ +#define B43_NPHY_IQEST_CMD B43_PHY_N(0x129) /* I/Q estimate command */ +#define B43_NPHY_IQEST_CMD_START 0x0001 /* Start */ +#define B43_NPHY_IQEST_CMD_MODE 0x0002 /* Mode */ +#define B43_NPHY_IQEST_WT B43_PHY_N(0x12A) /* I/Q estimate wait time */ +#define B43_NPHY_IQEST_WT_VAL 0x00FF /* Wait time */ +#define B43_NPHY_IQEST_WT_VAL_SHIFT 0 +#define B43_NPHY_IQEST_SAMCNT B43_PHY_N(0x12B) /* I/Q estimate sample count */ +#define B43_NPHY_IQEST_IQACC_LO0 B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */ +#define B43_NPHY_IQEST_IQACC_HI0 B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */ +#define B43_NPHY_IQEST_IPACC_LO0 B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */ +#define B43_NPHY_IQEST_IPACC_HI0 B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */ +#define B43_NPHY_IQEST_QPACC_LO0 B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */ +#define B43_NPHY_IQEST_QPACC_HI0 B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */ +#define B43_NPHY_IQEST_IQACC_LO1 B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */ +#define B43_NPHY_IQEST_IQACC_HI1 B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */ +#define B43_NPHY_IQEST_IPACC_LO1 B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */ +#define B43_NPHY_IQEST_IPACC_HI1 B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */ +#define B43_NPHY_IQEST_QPACC_LO1 B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */ +#define B43_NPHY_IQEST_QPACC_HI1 B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */ +#define B43_NPHY_MIMO_CRSTXEXT B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */ +#define B43_NPHY_PWRDET1 B43_PHY_N(0x13B) /* Power det 1 */ +#define B43_NPHY_PWRDET2 B43_PHY_N(0x13C) /* Power det 2 */ +#define B43_NPHY_MAXRSSI_DTIME B43_PHY_N(0x13F) /* RSSI max RSSI delay time */ +#define B43_NPHY_PIL_DW0 B43_PHY_N(0x141) /* Pilot data weight 0 */ +#define B43_NPHY_PIL_DW1 B43_PHY_N(0x142) /* Pilot data weight 1 */ +#define B43_NPHY_PIL_DW2 B43_PHY_N(0x143) /* Pilot data weight 2 */ +#define B43_NPHY_PIL_DW_BPSK 0x000F /* BPSK */ +#define B43_NPHY_PIL_DW_BPSK_SHIFT 0 +#define B43_NPHY_PIL_DW_QPSK 0x00F0 /* QPSK */ +#define B43_NPHY_PIL_DW_QPSK_SHIFT 4 +#define B43_NPHY_PIL_DW_16QAM 0x0F00 /* 16-QAM */ +#define B43_NPHY_PIL_DW_16QAM_SHIFT 8 +#define B43_NPHY_PIL_DW_64QAM 0xF000 /* 64-QAM */ +#define B43_NPHY_PIL_DW_64QAM_SHIFT 12 +#define B43_NPHY_FMDEM_CFG B43_PHY_N(0x144) /* FM demodulation config */ +#define B43_NPHY_PHASETR_A0 B43_PHY_N(0x145) /* Phase track alpha 0 */ +#define B43_NPHY_PHASETR_A1 B43_PHY_N(0x146) /* Phase track alpha 1 */ +#define B43_NPHY_PHASETR_A2 B43_PHY_N(0x147) /* Phase track alpha 2 */ +#define B43_NPHY_PHASETR_B0 B43_PHY_N(0x148) /* Phase track beta 0 */ +#define B43_NPHY_PHASETR_B1 B43_PHY_N(0x149) /* Phase track beta 1 */ +#define B43_NPHY_PHASETR_B2 B43_PHY_N(0x14A) /* Phase track beta 2 */ +#define B43_NPHY_PHASETR_CHG0 B43_PHY_N(0x14B) /* Phase track change 0 */ +#define B43_NPHY_PHASETR_CHG1 B43_PHY_N(0x14C) /* Phase track change 1 */ +#define B43_NPHY_PHASETW_OFF B43_PHY_N(0x14D) /* Phase track offset */ +#define B43_NPHY_RFCTL_DBG B43_PHY_N(0x14E) /* RF control debug */ +#define B43_NPHY_CCK_SHIFTB_REF B43_PHY_N(0x150) /* CCK shiftbits reference var */ +#define B43_NPHY_OVER_DGAIN0 B43_PHY_N(0x152) /* Override digital gain 0 */ +#define B43_NPHY_OVER_DGAIN1 B43_PHY_N(0x153) /* Override digital gain 1 */ +#define B43_NPHY_OVER_DGAIN_FDGV 0x0007 /* Force digital gain value */ +#define B43_NPHY_OVER_DGAIN_FDGV_SHIFT 0 +#define B43_NPHY_OVER_DGAIN_FDGEN 0x0008 /* Force digital gain enable */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV 0xFF00 /* CCK digital gain enable count value */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT 8 +#define B43_NPHY_BIST_STAT4 B43_PHY_N(0x156) /* BIST status 4 */ +#define B43_NPHY_RADAR_MAL B43_PHY_N(0x157) /* Radar MA length */ +#define B43_NPHY_RADAR_SRCCTL B43_PHY_N(0x158) /* Radar search control */ +#define B43_NPHY_VLD_DTSIG B43_PHY_N(0x159) /* VLD data tones sig */ +#define B43_NPHY_VLD_DTDAT B43_PHY_N(0x15A) /* VLD data tones data */ +#define B43_NPHY_C1_BPHY_RXIQCA0 B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */ +#define B43_NPHY_C1_BPHY_RXIQCB0 B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */ +#define B43_NPHY_C2_BPHY_RXIQCA1 B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */ +#define B43_NPHY_C2_BPHY_RXIQCB1 B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */ +#define B43_NPHY_FREQGAIN0 B43_PHY_N(0x160) /* Frequency gain 0 */ +#define B43_NPHY_FREQGAIN1 B43_PHY_N(0x161) /* Frequency gain 1 */ +#define B43_NPHY_FREQGAIN2 B43_PHY_N(0x162) /* Frequency gain 2 */ +#define B43_NPHY_FREQGAIN3 B43_PHY_N(0x163) /* Frequency gain 3 */ +#define B43_NPHY_FREQGAIN4 B43_PHY_N(0x164) /* Frequency gain 4 */ +#define B43_NPHY_FREQGAIN5 B43_PHY_N(0x165) /* Frequency gain 5 */ +#define B43_NPHY_FREQGAIN6 B43_PHY_N(0x166) /* Frequency gain 6 */ +#define B43_NPHY_FREQGAIN7 B43_PHY_N(0x167) /* Frequency gain 7 */ +#define B43_NPHY_FREQGAIN_BYPASS B43_PHY_N(0x168) /* Frequency gain bypass */ +#define B43_NPHY_TRLOSS B43_PHY_N(0x169) /* TR loss value */ +#define B43_NPHY_C1_ADCCLIP B43_PHY_N(0x16A) /* Core 1 ADC clip */ +#define B43_NPHY_C2_ADCCLIP B43_PHY_N(0x16B) /* Core 2 ADC clip */ +#define B43_NPHY_LTRN_OFFGAIN B43_PHY_N(0x16F) /* LTRN offset gain */ +#define B43_NPHY_LTRN_OFF B43_PHY_N(0x170) /* LTRN offset */ +#define B43_NPHY_NRDATAT_WWISE20SIG B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */ +#define B43_NPHY_NRDATAT_WWISE40SIG B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC20SIG B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC40SIG B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */ +#define B43_NPHY_WWISE_CRCM0 B43_PHY_N(0x175) /* WWiSE CRC mask 0 */ +#define B43_NPHY_WWISE_CRCM1 B43_PHY_N(0x176) /* WWiSE CRC mask 1 */ +#define B43_NPHY_WWISE_CRCM2 B43_PHY_N(0x177) /* WWiSE CRC mask 2 */ +#define B43_NPHY_WWISE_CRCM3 B43_PHY_N(0x178) /* WWiSE CRC mask 3 */ +#define B43_NPHY_WWISE_CRCM4 B43_PHY_N(0x179) /* WWiSE CRC mask 4 */ +#define B43_NPHY_CHANEST_CDDSH B43_PHY_N(0x17A) /* Channel estimate CDD shift */ +#define B43_NPHY_HTAGC_WCNT B43_PHY_N(0x17B) /* HT ADC wait counters */ +#define B43_NPHY_SQPARM B43_PHY_N(0x17C) /* SQ params */ +#define B43_NPHY_MCSDUP6M B43_PHY_N(0x17D) /* MCS dup 6M */ +#define B43_NPHY_NDATAT_DUP40 B43_PHY_N(0x17E) /* # data tones dup 40 */ +#define B43_NPHY_DUP40_TGNSYNC_CYCD B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */ +#define B43_NPHY_DUP40_GFBL B43_PHY_N(0x180) /* Dup40 GF format BL address */ +#define B43_NPHY_DUP40_BL B43_PHY_N(0x181) /* Dup40 format BL address */ +#define B43_NPHY_LEGDUP_FTA B43_PHY_N(0x182) /* Legacy dup frm table address */ +#define B43_NPHY_PACPROC_DBG B43_PHY_N(0x183) /* Packet processing debug */ +#define B43_NPHY_PIL_CYC1 B43_PHY_N(0x184) /* Pilot cycle counter 1 */ +#define B43_NPHY_PIL_CYC2 B43_PHY_N(0x185) /* Pilot cycle counter 2 */ +#define B43_NPHY_TXF_20CO_S0A1 B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */ +#define B43_NPHY_TXF_20CO_S0A2 B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */ +#define B43_NPHY_TXF_20CO_S1A1 B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */ +#define B43_NPHY_TXF_20CO_S1A2 B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */ +#define B43_NPHY_TXF_20CO_S2A1 B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */ +#define B43_NPHY_TXF_20CO_S2A2 B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */ +#define B43_NPHY_TXF_20CO_S0B1 B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */ +#define B43_NPHY_TXF_20CO_S0B2 B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */ +#define B43_NPHY_TXF_20CO_S0B3 B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */ +#define B43_NPHY_TXF_20CO_S1B1 B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */ +#define B43_NPHY_TXF_20CO_S1B2 B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */ +#define B43_NPHY_TXF_20CO_S1B3 B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */ +#define B43_NPHY_TXF_20CO_S2B1 B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */ +#define B43_NPHY_TXF_20CO_S2B2 B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */ +#define B43_NPHY_TXF_20CO_S2B3 B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */ +#define B43_NPHY_TXF_40CO_S0A1 B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */ +#define B43_NPHY_TXF_40CO_S0A2 B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */ +#define B43_NPHY_TXF_40CO_S1A1 B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */ +#define B43_NPHY_TXF_40CO_S1A2 B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */ +#define B43_NPHY_TXF_40CO_S2A1 B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */ +#define B43_NPHY_TXF_40CO_S2A2 B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */ +#define B43_NPHY_TXF_40CO_S0B1 B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */ +#define B43_NPHY_TXF_40CO_S0B2 B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */ +#define B43_NPHY_TXF_40CO_S0B3 B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */ +#define B43_NPHY_TXF_40CO_S1B1 B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */ +#define B43_NPHY_TXF_40CO_S1B2 B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */ +#define B43_NPHY_TXF_40CO_S1B3 B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */ +#define B43_NPHY_TXF_40CO_S2B1 B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */ +#define B43_NPHY_TXF_40CO_S2B2 B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */ +#define B43_NPHY_TXF_40CO_S2B3 B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */ +#define B43_NPHY_RSSIMC_0I_RSSI_X B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */ +#define B43_NPHY_RSSIMC_0I_RSSI_Y B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */ +#define B43_NPHY_RSSIMC_0I_RSSI_Z B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */ +#define B43_NPHY_RSSIMC_0I_TBD B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */ +#define B43_NPHY_RSSIMC_0I_PWRDET B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */ +#define B43_NPHY_RSSIMC_0I_TSSI B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */ +#define B43_NPHY_RSSIMC_0Q_RSSI_X B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Y B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Z B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */ +#define B43_NPHY_RSSIMC_0Q_TBD B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */ +#define B43_NPHY_RSSIMC_0Q_PWRDET B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */ +#define B43_NPHY_RSSIMC_0Q_TSSI B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */ +#define B43_NPHY_RSSIMC_1I_RSSI_X B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */ +#define B43_NPHY_RSSIMC_1I_RSSI_Y B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */ +#define B43_NPHY_RSSIMC_1I_RSSI_Z B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */ +#define B43_NPHY_RSSIMC_1I_TBD B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */ +#define B43_NPHY_RSSIMC_1I_PWRDET B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */ +#define B43_NPHY_RSSIMC_1I_TSSI B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */ +#define B43_NPHY_RSSIMC_1Q_RSSI_X B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Y B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Z B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */ +#define B43_NPHY_RSSIMC_1Q_TBD B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */ +#define B43_NPHY_RSSIMC_1Q_PWRDET B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */ +#define B43_NPHY_RSSIMC_1Q_TSSI B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */ +#define B43_NPHY_SAMC_WCNT B43_PHY_N(0x1BC) /* Sample collect wait counter */ +#define B43_NPHY_PTHROUGH_CNT B43_PHY_N(0x1BD) /* Pass-through counter */ +#define B43_NPHY_LTRN_OFF_G20L B43_PHY_N(0x1C4) /* LTRN offset gain 20L */ +#define B43_NPHY_LTRN_OFF_20L B43_PHY_N(0x1C5) /* LTRN offset 20L */ +#define B43_NPHY_LTRN_OFF_G20U B43_PHY_N(0x1C6) /* LTRN offset gain 20U */ +#define B43_NPHY_LTRN_OFF_20U B43_PHY_N(0x1C7) /* LTRN offset 20U */ +#define B43_NPHY_DSSSCCK_GAINSL B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */ +#define B43_NPHY_GPIO_LOOUT B43_PHY_N(0x1C9) /* GPIO low out */ +#define B43_NPHY_GPIO_HIOUT B43_PHY_N(0x1CA) /* GPIO high out */ +#define B43_NPHY_CRS_CHECK B43_PHY_N(0x1CB) /* CRS check */ +#define B43_NPHY_ML_LOGSS_RAT B43_PHY_N(0x1CC) /* ML/logss ratio */ +#define B43_NPHY_DUPSCALE B43_PHY_N(0x1CD) /* Dup scale */ +#define B43_NPHY_BW1A B43_PHY_N(0x1CE) /* BW 1A */ +#define B43_NPHY_BW2 B43_PHY_N(0x1CF) /* BW 2 */ +#define B43_NPHY_BW3 B43_PHY_N(0x1D0) /* BW 3 */ +#define B43_NPHY_BW4 B43_PHY_N(0x1D1) /* BW 4 */ +#define B43_NPHY_BW5 B43_PHY_N(0x1D2) /* BW 5 */ +#define B43_NPHY_BW6 B43_PHY_N(0x1D3) /* BW 6 */ +#define B43_NPHY_COALEN0 B43_PHY_N(0x1D4) /* Coarse length 0 */ +#define B43_NPHY_COALEN1 B43_PHY_N(0x1D5) /* Coarse length 1 */ +#define B43_NPHY_CRSTHRES_1U B43_PHY_N(0x1D6) /* CRS threshold 1 U */ +#define B43_NPHY_CRSTHRES_2U B43_PHY_N(0x1D7) /* CRS threshold 2 U */ +#define B43_NPHY_CRSTHRES_3U B43_PHY_N(0x1D8) /* CRS threshold 3 U */ +#define B43_NPHY_CRSCTL_U B43_PHY_N(0x1D9) /* CRS control U */ +#define B43_NPHY_CRSTHRES_1L B43_PHY_N(0x1DA) /* CRS threshold 1 L */ +#define B43_NPHY_CRSTHRES_2L B43_PHY_N(0x1DB) /* CRS threshold 2 L */ +#define B43_NPHY_CRSTHRES_3L B43_PHY_N(0x1DC) /* CRS threshold 3 L */ +#define B43_NPHY_CRSCTL_L B43_PHY_N(0x1DD) /* CRS control L */ +#define B43_NPHY_STRA_1U B43_PHY_N(0x1DE) /* STR address 1 U */ +#define B43_NPHY_STRA_2U B43_PHY_N(0x1DF) /* STR address 2 U */ +#define B43_NPHY_STRA_1L B43_PHY_N(0x1E0) /* STR address 1 L */ +#define B43_NPHY_STRA_2L B43_PHY_N(0x1E1) /* STR address 2 L */ +#define B43_NPHY_CRSCHECK1 B43_PHY_N(0x1E2) /* CRS check 1 */ +#define B43_NPHY_CRSCHECK2 B43_PHY_N(0x1E3) /* CRS check 2 */ +#define B43_NPHY_CRSCHECK3 B43_PHY_N(0x1E4) /* CRS check 3 */ +#define B43_NPHY_JMPSTP0 B43_PHY_N(0x1E5) /* Jump step 0 */ +#define B43_NPHY_JMPSTP1 B43_PHY_N(0x1E6) /* Jump step 1 */ +#define B43_NPHY_TXPCTL_CMD B43_PHY_N(0x1E7) /* TX power control command */ +#define B43_NPHY_TXPCTL_CMD_INIT 0x007F /* Init */ +#define B43_NPHY_TXPCTL_CMD_INIT_SHIFT 0 +#define B43_NPHY_TXPCTL_CMD_COEFF 0x2000 /* Power control coefficients */ +#define B43_NPHY_TXPCTL_CMD_HWPCTLEN 0x4000 /* Hardware TX power control enable */ +#define B43_NPHY_TXPCTL_CMD_PCTLEN 0x8000 /* TX power control enable */ +#define B43_NPHY_TXPCTL_N B43_PHY_N(0x1E8) /* TX power control N num */ +#define B43_NPHY_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */ +#define B43_NPHY_TXPCTL_N_TSSID_SHIFT 0 +#define B43_NPHY_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */ +#define B43_NPHY_TXPCTL_N_NPTIL2_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI B43_PHY_N(0x1E9) /* TX power control idle TSSI */ +#define B43_NPHY_TXPCTL_ITSSI_0 0x003F /* Idle TSSI 0 */ +#define B43_NPHY_TXPCTL_ITSSI_0_SHIFT 0 +#define B43_NPHY_TXPCTL_ITSSI_1 0x3F00 /* Idle TSSI 1 */ +#define B43_NPHY_TXPCTL_ITSSI_1_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI_BINF 0x8000 /* Raw TSSI offset bin format */ +#define B43_NPHY_TXPCTL_TPWR B43_PHY_N(0x1EA) /* TX power control target power */ +#define B43_NPHY_TXPCTL_TPWR_0 0x00FF /* Power 0 */ +#define B43_NPHY_TXPCTL_TPWR_0_SHIFT 0 +#define B43_NPHY_TXPCTL_TPWR_1 0xFF00 /* Power 1 */ +#define B43_NPHY_TXPCTL_TPWR_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX B43_PHY_N(0x1EB) /* TX power control base index */ +#define B43_NPHY_TXPCTL_BIDX_0 0x007F /* uC base index 0 */ +#define B43_NPHY_TXPCTL_BIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_BIDX_1 0x7F00 /* uC base index 1 */ +#define B43_NPHY_TXPCTL_BIDX_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX_LOAD 0x8000 /* Load base index */ +#define B43_NPHY_TXPCTL_PIDX B43_PHY_N(0x1EC) /* TX power control power index */ +#define B43_NPHY_TXPCTL_PIDX_0 0x007F /* uC power index 0 */ +#define B43_NPHY_TXPCTL_PIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_PIDX_1 0x7F00 /* uC power index 1 */ +#define B43_NPHY_TXPCTL_PIDX_1_SHIFT 8 +#define B43_NPHY_C1_TXPCTL_STAT B43_PHY_N(0x1ED) /* Core 1 TX power control status */ +#define B43_NPHY_C2_TXPCTL_STAT B43_PHY_N(0x1EE) /* Core 2 TX power control status */ +#define B43_NPHY_TXPCTL_STAT_EST 0x00FF /* Estimated power */ +#define B43_NPHY_TXPCTL_STAT_EST_SHIFT 0 +#define B43_NPHY_TXPCTL_STAT_BIDX 0x7F00 /* Base index */ +#define B43_NPHY_TXPCTL_STAT_BIDX_SHIFT 8 +#define B43_NPHY_TXPCTL_STAT_ESTVALID 0x8000 /* Estimated power valid */ +#define B43_NPHY_SMALLSGS_LEN B43_PHY_N(0x1EF) /* Small sig gain settle length */ +#define B43_NPHY_PHYSTAT_GAIN0 B43_PHY_N(0x1F0) /* PHY stats gain info 0 */ +#define B43_NPHY_PHYSTAT_GAIN1 B43_PHY_N(0x1F1) /* PHY stats gain info 1 */ +#define B43_NPHY_PHYSTAT_FREQEST B43_PHY_N(0x1F2) /* PHY stats frequency estimate */ +#define B43_NPHY_PHYSTAT_ADVRET B43_PHY_N(0x1F3) /* PHY stats ADV retard */ +#define B43_NPHY_PHYLB_MODE B43_PHY_N(0x1F4) /* PHY loopback mode */ +#define B43_NPHY_TONE_MIDX20_1 B43_PHY_N(0x1F5) /* Tone map index 20/1 */ +#define B43_NPHY_TONE_MIDX20_2 B43_PHY_N(0x1F6) /* Tone map index 20/2 */ +#define B43_NPHY_TONE_MIDX20_3 B43_PHY_N(0x1F7) /* Tone map index 20/3 */ +#define B43_NPHY_TONE_MIDX40_1 B43_PHY_N(0x1F8) /* Tone map index 40/1 */ +#define B43_NPHY_TONE_MIDX40_2 B43_PHY_N(0x1F9) /* Tone map index 40/2 */ +#define B43_NPHY_TONE_MIDX40_3 B43_PHY_N(0x1FA) /* Tone map index 40/3 */ +#define B43_NPHY_TONE_MIDX40_4 B43_PHY_N(0x1FB) /* Tone map index 40/4 */ +#define B43_NPHY_PILTONE_MIDX1 B43_PHY_N(0x1FC) /* Pilot tone map index 1 */ +#define B43_NPHY_PILTONE_MIDX2 B43_PHY_N(0x1FD) /* Pilot tone map index 2 */ +#define B43_NPHY_PILTONE_MIDX3 B43_PHY_N(0x1FE) /* Pilot tone map index 3 */ +#define B43_NPHY_TXRIFS_FRDEL B43_PHY_N(0x1FF) /* TX RIFS frame delay */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_40M B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_40M B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_20M B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_20M B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */ +#define B43_NPHY_RX_SIGCTL B43_PHY_N(0x204) /* RX signal control */ +#define B43_NPHY_RXPIL_CYCNT0 B43_PHY_N(0x205) /* RX pilot cycle counter 0 */ +#define B43_NPHY_RXPIL_CYCNT1 B43_PHY_N(0x206) /* RX pilot cycle counter 1 */ +#define B43_NPHY_RXPIL_CYCNT2 B43_PHY_N(0x207) /* RX pilot cycle counter 2 */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_10M B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_10M B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */ +#define B43_NPHY_DSSSCCK_CRSEXTL B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */ +#define B43_NPHY_ML_LOGSS_RATSLOPE B43_PHY_N(0x20B) /* ML/logss ratio slope */ +#define B43_NPHY_RIFS_SRCTL B43_PHY_N(0x20C) /* RIFS search timeout length */ +#define B43_NPHY_TXREALFD B43_PHY_N(0x20D) /* TX real frame delay */ +#define B43_NPHY_HPANT_SWTHRES B43_PHY_N(0x20E) /* High power antenna switch threshold */ +#define B43_NPHY_EDCRS_ASSTHRES0 B43_PHY_N(0x210) /* ED CRS assert threshold 0 */ +#define B43_NPHY_EDCRS_ASSTHRES1 B43_PHY_N(0x211) /* ED CRS assert threshold 1 */ +#define B43_NPHY_EDCRS_DEASSTHRES0 B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */ +#define B43_NPHY_EDCRS_DEASSTHRES1 B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */ +#define B43_NPHY_STR_WTIME20U B43_PHY_N(0x214) /* STR wait time 20U */ +#define B43_NPHY_STR_WTIME20L B43_PHY_N(0x215) /* STR wait time 20L */ +#define B43_NPHY_TONE_MIDX657M B43_PHY_N(0x216) /* Tone map index 657M */ +#define B43_NPHY_HTSIGTONES B43_PHY_N(0x217) /* HT signal tones */ +#define B43_NPHY_RSSI1 B43_PHY_N(0x219) /* RSSI value 1 */ +#define B43_NPHY_RSSI2 B43_PHY_N(0x21A) /* RSSI value 2 */ +#define B43_NPHY_CHAN_ESTHANG B43_PHY_N(0x21D) /* Channel estimate hang */ +#define B43_NPHY_FINERX2_CGC B43_PHY_N(0x221) /* Fine RX 2 clock gate control */ +#define B43_NPHY_FINERX2_CGC_DECGC 0x0008 /* Decode gated clocks */ +#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 + + + +/* Broadcom 2055 radio registers */ + +#define B2055_GEN_SPARE 0x00 /* GEN spare */ +#define B2055_SP_PINPD 0x02 /* SP PIN PD */ +#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ +#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ +#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ +#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ +#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ +#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ +#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ +#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ +#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ +#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ +#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ +#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ +#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ +#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ +#define B2055_MASTER1 0x11 /* Master control 1 */ +#define B2055_MASTER2 0x12 /* Master control 2 */ +#define B2055_PD_LGEN 0x13 /* PD LGEN */ +#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ +#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ +#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ +#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ +#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ +#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ +#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ +#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ +#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ +#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ +#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ +#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ +#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ +#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ +#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ +#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ +#define B2055_CAL_MISC 0x24 /* CAL MISC */ +#define B2055_CAL_COUT 0x25 /* CAL Counter out */ +#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ +#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ +#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ +#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ +#define B2055_CAL_TS 0x2A /* CAL TS */ +#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ +#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ +#define B2055_PADDRV 0x2D /* PAD driver */ +#define B2055_XOCTL1 0x2E /* XO Control 1 */ +#define B2055_XOCTL2 0x2F /* XO Control 2 */ +#define B2055_XOREGUL 0x30 /* XO Regulator */ +#define B2055_XOMISC 0x31 /* XO misc */ +#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ +#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ +#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ +#define B2055_PLL_REF 0x35 /* PLL reference */ +#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ +#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ +#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ +#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ +#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ +#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ +#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ +#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ +#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ +#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ +#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ +#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ +#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ +#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ +#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ +#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ +#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ +#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ +#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ +#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ +#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ +#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ +#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ +#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ +#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ +#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ +#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ +#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ +#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ +#define B2055_VCO_REG 0x53 /* VCO Regulator */ +#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ +#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ +#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ +#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ +#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ +#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ +#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ +#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ +#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ +#define B2055_LGEN_DIV 0x5D /* LGEN div */ +#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ +#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ +#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ +#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ +#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ +#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ +#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ +#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ +#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ +#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ +#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ +#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ +#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ +#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ +#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ +#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ +#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ +#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ +#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ +#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ +#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ +#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ +#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ +#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ +#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ +#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ +#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ +#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ +#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ +#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ +#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ +#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ +#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ +#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ +#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ +#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ +#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ +#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ +#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ +#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ +#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ +#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ +#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ +#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ +#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ +#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ +#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ +#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ +#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ +#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ +#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ +#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ +#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ +#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ +#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ +#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ +#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ +#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ +#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ +#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ +#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ +#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ +#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ +#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ +#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ +#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ +#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ +#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ +#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ +#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ +#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ +#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ +#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ +#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ +#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ +#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ +#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ +#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ +#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ +#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ +#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ +#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ +#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ +#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ +#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ +#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ +#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ +#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ +#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ +#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ +#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ +#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ +#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ +#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ +#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ +#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ +#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ +#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ +#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ +#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ +#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ +#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ +#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ +#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ +#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ +#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ +#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ +#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ +#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ +#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ +#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ + + + +struct b43_wldev; + +int b43_phy_initn(struct b43_wldev *dev); + +void b43_nphy_radio_turn_on(struct b43_wldev *dev); +void b43_nphy_radio_turn_off(struct b43_wldev *dev); + +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); + +void b43_nphy_xmitpower(struct b43_wldev *dev); +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); + +#endif /* B43_NPHY_H_ */ diff --git a/package/b43/src/pcmcia.c b/package/b43/src/pcmcia.c index b242a9a90d..b79a6bd539 100644 --- a/package/b43/src/pcmcia.c +++ b/package/b43/src/pcmcia.c @@ -65,12 +65,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) tuple_t tuple; cisparse_t parse; int err = -ENOMEM; - int res; + int res = 0; unsigned char buf[64]; ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); if (!ssb) - goto out; + goto out_error; err = -ENODEV; tuple.DesiredTuple = CISTPL_CONFIG; @@ -96,10 +96,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) dev->io.NumPorts2 = 0; dev->io.Attributes2 = 0; - win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM | + WIN_ENABLE | WIN_DATA_WIDTH_16 | + WIN_USE_WAIT; win.Base = 0; win.Size = SSB_CORE_SIZE; - win.AccessSpeed = 1000; + win.AccessSpeed = 250; res = pcmcia_request_window(&dev, &win, &dev->win); if (res != CS_SUCCESS) goto err_kfree_ssb; @@ -108,21 +110,34 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) mem.Page = 0; res = pcmcia_map_mem_page(dev->win, &mem); if (res != CS_SUCCESS) - goto err_kfree_ssb; + goto err_disable; + + dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED; + dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID; + dev->irq.Handler = NULL; /* The handler is registered later. */ + dev->irq.Instance = NULL; + res = pcmcia_request_irq(dev, &dev->irq); + if (res != CS_SUCCESS) + goto err_disable; res = pcmcia_request_configuration(dev, &dev->conf); if (res != CS_SUCCESS) goto err_disable; err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); + if (err) + goto err_disable; dev->priv = ssb; - out: - return err; - err_disable: + return 0; + +err_disable: pcmcia_disable_device(dev); - err_kfree_ssb: +err_kfree_ssb: kfree(ssb); +out_error: + printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n", + res, err); return err; } @@ -131,22 +146,21 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev) struct ssb_bus *ssb = dev->priv; ssb_bus_unregister(ssb); - pcmcia_release_window(dev->win); pcmcia_disable_device(dev); kfree(ssb); dev->priv = NULL; } static struct pcmcia_driver b43_pcmcia_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "b43-pcmcia", - }, - .id_table = b43_pcmcia_tbl, - .probe = b43_pcmcia_probe, - .remove = b43_pcmcia_remove, - .suspend = b43_pcmcia_suspend, - .resume = b43_pcmcia_resume, + .owner = THIS_MODULE, + .drv = { + .name = "b43-pcmcia", + }, + .id_table = b43_pcmcia_tbl, + .probe = b43_pcmcia_probe, + .remove = __devexit_p(b43_pcmcia_remove), + .suspend = b43_pcmcia_suspend, + .resume = b43_pcmcia_resume, }; int b43_pcmcia_init(void) diff --git a/package/b43/src/phy.c b/package/b43/src/phy.c index 3d4ed647c3..71507b260b 100644 --- a/package/b43/src/phy.c +++ b/package/b43/src/phy.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -31,9 +31,12 @@ #include "b43.h" #include "phy.h" +#include "nphy.h" #include "main.h" #include "tables.h" #include "lo.h" +#include "wa.h" + static const s8 b43_tssi2dbm_b_table[] = { 0x4D, 0x4C, 0x4B, 0x4A, @@ -225,42 +228,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev) } } -void b43_raw_phy_lock(struct b43_wldev *dev) +/* Lock the PHY registers against concurrent access from the microcode. + * This lock is nonrecursive. */ +void b43_phy_lock(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - B43_WARN_ON(!irqs_disabled()); - - /* We had a check for MACCTL==0 here, but I think that doesn't - * make sense, as MACCTL is never 0 when this is called. - * --mb */ - B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0); +#if B43_DEBUG + B43_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); - if (dev->dev->id.revision < 3) { - b43_mac_suspend(dev); - spin_lock(&phy->lock); - } else { - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); - } - phy->locked = 1; + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); } -void b43_raw_phy_unlock(struct b43_wldev *dev) +void b43_phy_unlock(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; +#if B43_DEBUG + B43_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); - B43_WARN_ON(!irqs_disabled()); - if (dev->dev->id.revision < 3) { - if (phy->locked) { - spin_unlock(&phy->lock); - b43_mac_enable(dev); - } - } else { - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, 0); - } - phy->locked = 0; + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); } /* Different PHYs require different register routing flags. @@ -271,15 +262,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, { if (phy->type == B43_PHYTYPE_A) { /* OFDM registers are base-registers for the A-PHY. */ - offset &= ~B43_PHYROUTE_OFDM_GPHY; + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + offset &= ~B43_PHYROUTE; + offset |= B43_PHYROUTE_BASE; + } } - if (offset & B43_PHYROUTE_EXT_GPHY) { + +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { /* Ext-G registers are only available on G-PHYs */ if (phy->type != B43_PHYTYPE_G) { - b43dbg(dev->wl, "EXT-G PHY access at " - "0x%04X on %u type PHY\n", offset, phy->type); + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on PHY type %u\n", offset, phy->type); + dump_stack(); } } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { + /* N-BMODE registers are only available on N-PHYs */ + if (phy->type != B43_PHYTYPE_N) { + b43err(dev->wl, "Invalid N-BMODE PHY access at " + "0x%04X on PHY type %u\n", offset, phy->type); + dump_stack(); + } + } +#endif /* B43_DEBUG */ return offset; } @@ -299,11 +305,26 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) offset = adjust_phyreg_for_phytype(phy, offset, dev); b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - mmiowb(); b43_write16(dev, B43_MMIO_PHY_DATA, val); } -static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower); +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); +} + +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); +} + +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); +} /* Adjust the transmission power output (G-PHY) */ void b43_set_txpower_g(struct b43_wldev *dev, @@ -763,366 +784,96 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) b43_shm_clear_tssi(dev); } -static void b43_phy_agcsetup(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset = 0x0000; - - if (phy->rev == 1) - offset = 0x4C00; - - b43_ofdmtab_write16(dev, offset, 0, 0x00FE); - b43_ofdmtab_write16(dev, offset, 1, 0x000D); - b43_ofdmtab_write16(dev, offset, 2, 0x0013); - b43_ofdmtab_write16(dev, offset, 3, 0x0019); - - if (phy->rev == 1) { - b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710); - b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83); - b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83); - b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D); - b43_phy_write(dev, 0x0455, 0x0004); - } - - b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5) - & 0x00FF) | 0x5700); - b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) - & 0xFF80) | 0x000F); - b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) - & 0xC07F) | 0x2B80); - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xF0FF) | 0x0300); - - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) - | 0x0008); - - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xFFF0) | 0x0008); - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xF0FF) | 0x0600); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xF0FF) | 0x0700); - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xF0FF) | 0x0100); - - if (phy->rev == 1) { - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xFFF0) | 0x0007); - } - - b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) - & 0xFF00) | 0x001C); - b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) - & 0xC0FF) | 0x0200); - b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) - & 0xFF00) | 0x001C); - b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) - & 0xFF00) | 0x0020); - b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) - & 0xC0FF) | 0x0200); - b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482) - & 0xFF00) | 0x002E); - b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) - & 0x00FF) | 0x1A00); - b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) - & 0xFF00) | 0x0028); - b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) - & 0x00FF) | 0x2C00); - - if (phy->rev == 1) { - b43_phy_write(dev, 0x0430, 0x092B); - b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B) - & 0xFFE1) | 0x0002); - } else { - b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B) - & 0xFFE1); - b43_phy_write(dev, 0x041F, 0x287A); - b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) - & 0xFFF0) | 0x0004); - } - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0422, 0x287A); - b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) - & 0x0FFF) | 0x3000); - } - - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0x8080) | 0x7874); - b43_phy_write(dev, 0x048E, 0x1C00); - - offset = 0x0800; - if (phy->rev == 1) { - offset = 0x5400; - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xF0FF) | 0x0600); - b43_phy_write(dev, 0x048B, 0x005E); - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xFF00) | 0x001E); - b43_phy_write(dev, 0x048D, 0x0002); - } - b43_ofdmtab_write16(dev, offset, 0, 0x00); - b43_ofdmtab_write16(dev, offset, 1, 0x07); - b43_ofdmtab_write16(dev, offset, 2, 0x10); - b43_ofdmtab_write16(dev, offset, 3, 0x1C); - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) - & 0xFFFC); - b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) - & 0xEFFF); - } -} - -static void b43_phy_setupg(struct b43_wldev *dev) +static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) { - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - u16 i; - - B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if (phy->rev == 1) { - b43_phy_write(dev, 0x0406, 0x4F19); - b43_phy_write(dev, B43_PHY_G_CRS, - (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) | - 0x0340); - b43_phy_write(dev, 0x042C, 0x005A); - b43_phy_write(dev, 0x0427, 0x001A); - - for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5800, i, - b43_tab_finefreqg[i]); - for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]); - for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]); - } else { - /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ - b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654); - - if (phy->rev == 2) { - b43_phy_write(dev, 0x04C0, 0x1861); - b43_phy_write(dev, 0x04C1, 0x0271); - } else if (phy->rev > 2) { - b43_phy_write(dev, 0x04C0, 0x0098); - b43_phy_write(dev, 0x04C1, 0x0070); - b43_phy_write(dev, 0x04C9, 0x0080); - } - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800); - - for (i = 0; i < 64; i++) - b43_ofdmtab_write16(dev, 0x4000, i, i); - for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]); - } - - if (phy->rev <= 2) - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg1[i]); - else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200)) - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg3[i]); - else - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg2[i]); - - if (phy->rev == 2) - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr1[i]); - else if ((phy->rev > 2) && (phy->rev <= 8)) - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr2[i]); - - if (phy->rev == 1) { - for (i = 0; i < B43_TAB_RETARD_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); - for (i = 4; i < 20; i++) - b43_ofdmtab_write16(dev, 0x5400, i, 0x0020); - b43_phy_agcsetup(dev); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306) && - (bus->boardinfo.rev == 0x17)) - return; - - b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002); - b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001); - } else { - for (i = 0; i < 0x20; i++) - b43_ofdmtab_write16(dev, 0x1000, i, 0x0820); - b43_phy_agcsetup(dev); - b43_phy_read(dev, 0x0400); /* dummy read */ - b43_phy_write(dev, 0x0403, 0x1000); - b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306) && - (bus->boardinfo.rev == 0x17)) - return; - - b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002); - b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001); - } -} - -/* Initialize the noisescaletable for APHY */ -static void b43_phy_init_noisescaletbl(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; int i; - for (i = 0; i < 12; i++) { - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + if (dev->phy.rev < 3) { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0xFFF8); + } else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); - } - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6700); - else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2300); - for (i = 0; i < 11; i++) { - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); + } + } else { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0x0820); else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); } - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x0067); - else - b43_ofdmtab_write16(dev, 0x1400, i, 0x0023); } -static void b43_phy_setupa(struct b43_wldev *dev) +static void b43_phy_ww(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - u16 i; - - B43_WARN_ON(phy->type != B43_PHYTYPE_A); - switch (phy->rev) { - case 2: - b43_phy_write(dev, 0x008E, 0x3800); - b43_phy_write(dev, 0x0035, 0x03FF); - b43_phy_write(dev, 0x0036, 0x0400); - - b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); - - b43_phy_write(dev, 0x001C, 0x0FF9); - b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); - b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF); - b43_radio_write16(dev, 0x0002, 0x07BF); - - b43_phy_write(dev, 0x0024, 0x4680); - b43_phy_write(dev, 0x0020, 0x0003); - b43_phy_write(dev, 0x001D, 0x0F40); - b43_phy_write(dev, 0x001F, 0x1C00); - - b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) - & 0x00FF) | 0x0400); - b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) - & 0xFBFF); - b43_phy_write(dev, 0x008E, 0x58C1); - - b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); - b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); - - b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015); - b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015); - b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019); - - b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); - - for (i = 0; i < 16; i++) - b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F); - - b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044); - b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201); - b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040); - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) & - 0x0010) | 0x0008); - - for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5800, i, - b43_tab_finefreqa[i]); - for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]); - for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]); - b43_phy_init_noisescaletbl(dev); - for (i = 0; i < B43_TAB_RETARD_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); - break; - case 3: - for (i = 0; i < 64; i++) - b43_ofdmtab_write16(dev, 0x4000, i, i); - - b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); - - b43_phy_write(dev, 0x001C, 0x0FF9); - b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); - b43_radio_write16(dev, 0x0002, 0x07BF); - - b43_phy_write(dev, 0x0024, 0x4680); - b43_phy_write(dev, 0x0020, 0x0003); - b43_phy_write(dev, 0x001D, 0x0F40); - b43_phy_write(dev, 0x001F, 0x1C00); - b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) - & 0x00FF) | 0x0400); - - b43_ofdmtab_write16(dev, 0x3000, 1, - (b43_ofdmtab_read16(dev, 0x3000, 1) - & 0x0010) | 0x0008); - for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) { - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]); - } - b43_phy_init_noisescaletbl(dev); - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr1[i]); - } - - b43_phy_write(dev, 0x0003, 0x1808); - - b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); - b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); - - b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015); - b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015); - b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019); - - b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + u16 b, curr_s, best_s = 0xFFFF; + int i; - b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); - break; - default: - B43_WARN_ON(1); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x0009, + b43_radio_read16(dev, 0x0009) | 0x0080); + b43_radio_write16(dev, 0x0012, + (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); + b43_wa_initgains(dev); + b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); + b = b43_phy_read(dev, B43_PHY_PWRDOWN); + b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) | 0x0004); + for (i = 0x10; i <= 0x20; i++) { + b43_radio_write16(dev, 0x0013, i); + curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; + if (!curr_s) { + best_s = 0x0000; + break; + } else if (curr_s >= 0x0080) + curr_s = 0x0100 - curr_s; + if (curr_s < best_s) + best_s = curr_s; } + b43_phy_write(dev, B43_PHY_PWRDOWN, b); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) & 0xFFFB); + b43_radio_write16(dev, 0x0013, best_s); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); + b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); + b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); + b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); + b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); + b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); + b43_phy_write(dev, B43_PHY_OFDM(0xBB), + (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); + b43_phy_write(dev, B43_PHY_OFDM61, + (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120); + b43_phy_write(dev, B43_PHY_OFDM(0x13), + (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); + b43_phy_write(dev, B43_PHY_OFDM(0x14), + (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); + for (i = 0; i < 6; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); + b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); } /* Initialize APHY. This is also called for the GPHY in some cases. */ @@ -1130,64 +881,54 @@ static void b43_phy_inita(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; - u16 tval; might_sleep(); - if (phy->type == B43_PHYTYPE_A) { - b43_phy_setupa(dev); - } else { - b43_phy_setupg(dev); - if (phy->gmode && - (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)) - b43_phy_write(dev, 0x046E, 0x03CF); - return; + if (phy->rev >= 6) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); + else + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); } - b43_phy_write(dev, B43_PHY_A_CRS, - (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340); - b43_phy_write(dev, 0x0034, 0x0001); + b43_wa_all(dev); - //TODO: RSSI AGC - b43_phy_write(dev, B43_PHY_A_CRS, - b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14)); - b43_radio_init2060(dev); + if (phy->type == B43_PHYTYPE_A) { + if (phy->gmode && (phy->rev < 3)) + b43_phy_write(dev, 0x0034, + b43_phy_read(dev, 0x0034) | 0x0001); + b43_phy_rssiagc(dev, 0); - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { - if (phy->lofcal == 0xFFFF) { - //TODO: LOF Cal - b43_radio_set_tx_iq(dev); - } else - b43_radio_write16(dev, 0x001E, phy->lofcal); - } + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); - b43_phy_write(dev, 0x007A, 0xF111); + b43_radio_init2060(dev); - if (phy->cur_idle_tssi == 0) { - b43_radio_write16(dev, 0x0019, 0x0000); - b43_radio_write16(dev, 0x0017, 0x0020); - - tval = b43_ofdmtab_read16(dev, 0x3001, 0); - if (phy->rev == 1) { - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) - & 0xFF87) - | 0x0058); - } else { - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) - & 0xFFC3) - | 0x002C); + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + ; //TODO: A PHY LO } - b43_dummy_transmission(dev); - phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL); - b43_ofdmtab_write16(dev, 0x3001, 0, tval); - b43_radio_set_txpower_a(dev, 0x0018); + if (phy->rev >= 3) + b43_phy_ww(dev); + + hardware_pctl_init_aphy(dev); + + //TODO: radar detection + } + + if ((phy->type == B43_PHYTYPE_G) && + (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + b43_phy_write(dev, B43_PHY_OFDM(0x6E), + (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) + & 0xE000) | 0x3CF); } - b43_shm_clear_tssi(dev); } static void b43_phy_initb2(struct b43_wldev *dev) @@ -1286,7 +1027,7 @@ static void b43_phy_initb4(struct b43_wldev *dev) if (phy->radio_ver == 0x2050) b43_phy_write(dev, 0x002A, 0x88C2); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_calc_nrssi_slope(dev); b43_calc_nrssi_threshold(dev); } @@ -1433,7 +1174,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_radio_write16(dev, 0x5A, 0x88); b43_radio_write16(dev, 0x5B, 0x6B); b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { b43_radio_write16(dev, 0x5D, 0xFA); b43_radio_write16(dev, 0x5E, 0xD8); } else { @@ -1525,7 +1266,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x0062, 0x0007); b43_radio_init2050(dev); b43_lo_g_measure(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_calc_nrssi_slope(dev); b43_calc_nrssi_threshold(dev); } @@ -1552,14 +1293,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); } - backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A)); - backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59)); - backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58)); - backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A)); - backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03)); + backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); - backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B)); + backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); backup_bband = phy->bbatt.att; @@ -1601,12 +1342,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) (b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFCF) | 0x10); - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - b43_phy_write(dev, B43_PHY_BASE(0x0A), - b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000); + b43_phy_write(dev, B43_PHY_CCK(0x0A), + b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ b43_phy_write(dev, B43_PHY_ANALOGOVER, b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); @@ -1614,8 +1355,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) & 0xFFFB); } - b43_phy_write(dev, B43_PHY_BASE(0x03), - (b43_phy_read(dev, B43_PHY_BASE(0x03)) + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) & 0xFF9F) | 0x40); if (phy->radio_rev == 8) { @@ -1633,11 +1374,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); b43_phy_write(dev, B43_PHY_LO_CTL, 0); - b43_phy_write(dev, B43_PHY_BASE(0x2B), - (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) & 0xFFC0) | 0x01); - b43_phy_write(dev, B43_PHY_BASE(0x2B), - (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) & 0xC0FF) | 0x800); b43_phy_write(dev, B43_PHY_RFOVER, @@ -1645,7 +1386,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_RFOVERVAL, b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { if (phy->rev >= 7) { b43_phy_write(dev, B43_PHY_RFOVER, b43_phy_read(dev, B43_PHY_RFOVER) @@ -1708,14 +1449,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); } - b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]); - b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]); - b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]); - b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]); - b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); - b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); b43_phy_set_baseband_attenuation(dev, backup_bband); @@ -1807,26 +1548,26 @@ static void b43_phy_initg(struct b43_wldev *dev) | phy->lo_control->tx_bias); } if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_BASE(0x36), - (b43_phy_read(dev, B43_PHY_BASE(0x36)) + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) & 0x0FFF) | (phy->lo_control-> tx_bias << 12)); } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075); + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); else - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); else - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); } if (phy->gmode || phy->rev >= 2) { b43_lo_g_adjust(dev); b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } - if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { /* The specs state to update the NRSSI LT with * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. @@ -1995,7 +1736,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev) int rfatt_delta, bbatt_delta; int rfatt, bbatt; u8 tx_control; - unsigned long phylock_flags; tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); v0 = (s8) (tmp & 0x00FF); @@ -2036,16 +1776,15 @@ void b43_phy_xmitpower(struct b43_wldev *dev) estimated_pwr = b43_phy_estimate_power_out(dev, average); - max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; - if ((dev->dev->bus->sprom.r1. - boardflags_lo & B43_BFL_PACTRL) - && (phy->type == B43_PHYTYPE_G)) + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) max_pwr -= 0x3; if (unlikely(max_pwr <= 0)) { b43warn(dev->wl, "Invalid max-TX-power value in SPROM.\n"); max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + dev->dev->bus->sprom.maxpwr_bg = max_pwr; } /*TODO: @@ -2103,7 +1842,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev) B43_TXCTL_TXMIX; rfatt += 2; bbatt += 2; - } else if (dev->dev->bus->sprom.r1. + } else if (dev->dev->bus->sprom. boardflags_lo & B43_BFL_PACTRL) { bbatt += 4 * (rfatt - 2); @@ -2127,15 +1866,18 @@ void b43_phy_xmitpower(struct b43_wldev *dev) phy->bbatt.att = bbatt; /* Adjust the hardware */ - b43_phy_lock(dev, phylock_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); b43_lo_g_ctl_mark_cur_used(dev); b43_radio_unlock(dev); - b43_phy_unlock(dev, phylock_flags); + b43_phy_unlock(dev); break; } + case B43_PHYTYPE_N: + b43_nphy_xmitpower(dev); + break; default: B43_WARN_ON(1); } @@ -2179,13 +1921,13 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) s8 *dyn_tssi2dbm; if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2); + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); } else { - pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2); + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); } if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { @@ -2198,23 +1940,23 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 && - (s8) dev->dev->bus->sprom.r1.itssi_a != -1) + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.r1.itssi_a); + (s8) (dev->dev->bus->sprom.itssi_a); else phy->tgt_idle_tssi = 62; } else { - if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.r1.itssi_bg != -1) + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.r1.itssi_bg); + (s8) (dev->dev->bus->sprom.itssi_bg); else phy->tgt_idle_tssi = 62; } dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); if (dyn_tssi2dbm == NULL) { - b43err(dev->wl, "Could not allocate memory" + b43err(dev->wl, "Could not allocate memory " "for tssi2dbm table\n"); return -ENOMEM; } @@ -2255,41 +1997,44 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) int b43_phy_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err = -ENODEV; + bool unsupported = 0; + int err = 0; switch (phy->type) { case B43_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) { + if (phy->rev == 2 || phy->rev == 3) b43_phy_inita(dev); - err = 0; - } + else + unsupported = 1; break; case B43_PHYTYPE_B: switch (phy->rev) { case 2: b43_phy_initb2(dev); - err = 0; break; case 4: b43_phy_initb4(dev); - err = 0; break; case 5: b43_phy_initb5(dev); - err = 0; break; case 6: b43_phy_initb6(dev); - err = 0; break; + default: + unsupported = 1; } break; case B43_PHYTYPE_G: b43_phy_initg(dev); - err = 0; break; + case B43_PHYTYPE_N: + err = b43_phy_initn(dev); + break; + default: + unsupported = 1; } - if (err) + if (unsupported) b43err(dev->wl, "Unknown PHYTYPE found\n"); return err; @@ -2392,6 +2137,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); break; + case B43_PHYTYPE_N: + b43_nphy_set_rxantenna(dev, antenna); + break; default: B43_WARN_ON(1); } @@ -2421,6 +2169,7 @@ void b43_radio_lock(struct b43_wldev *dev) u32 macctl; macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); macctl |= B43_MACCTL_RADIOLOCK; b43_write32(dev, B43_MMIO_MACCTL, macctl); /* Commit the write and wait for the device @@ -2437,6 +2186,7 @@ void b43_radio_unlock(struct b43_wldev *dev) b43_read16(dev, B43_MMIO_PHY_VER); /* unlock */ macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); macctl &= ~B43_MACCTL_RADIOLOCK; b43_write32(dev, B43_MMIO_MACCTL, macctl); } @@ -2445,9 +2195,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) { struct b43_phy *phy = &dev->phy; + /* Offset 1 is a 32-bit register. */ + B43_WARN_ON(offset == 1); + switch (phy->type) { case B43_PHYTYPE_A: - offset |= 0x0040; + offset |= 0x40; break; case B43_PHYTYPE_B: if (phy->radio_ver == 0x2053) { @@ -2463,6 +2216,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) case B43_PHYTYPE_G: offset |= 0x80; break; + case B43_PHYTYPE_N: + offset |= 0x100; + break; + case B43_PHYTYPE_LP: + /* No adjustment required. */ + break; + default: + B43_WARN_ON(1); } b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); @@ -2471,11 +2232,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) { + /* Offset 1 is a 32-bit register. */ + B43_WARN_ON(offset == 1); + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - mmiowb(); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); } +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) & mask); +} + +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) | set); +} + +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_radio_write16(dev, offset, + (b43_radio_read16(dev, offset) & mask) | set); +} + static void b43_set_all_gains(struct b43_wldev *dev, s16 first, s16 second, s16 third) { @@ -2605,12 +2386,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev) u8 ret[13]; unsigned int channel = phy->channel; unsigned int i, j, start, end; - unsigned long phylock_flags; if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) return 0; - b43_phy_lock(dev, phylock_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); b43_phy_write(dev, B43_PHY_G_CRS, @@ -2639,7 +2419,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev) ret[j] = 1; } b43_radio_unlock(dev); - b43_phy_unlock(dev, phylock_flags); + b43_phy_unlock(dev); return ret[channel - 1]; } @@ -3114,7 +2894,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) if (phy->radio_ver != 0x2050) return; if (! - (dev->dev->bus->sprom.r1. + (dev->dev->bus->sprom. boardflags_lo & B43_BFL_RSSI)) return; @@ -3145,7 +2925,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) } case B43_PHYTYPE_G: if (!phy->gmode || - !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { tmp16 = b43_nrssi_hw_read(dev, 0x20); if (tmp16 >= 0x20) tmp16 -= 0x40; @@ -3667,7 +3447,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, } if ((phy->rev < 7) || - !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { if (phy_register == B43_PHY_RFOVER) { return 0x1B3; } else if (phy_register == B43_PHY_RFOVERVAL) { @@ -3707,7 +3487,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, } } else { if ((phy->rev < 7) || - !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { if (phy_register == B43_PHY_RFOVER) { return 0x1B3; } else if (phy_register == B43_PHY_RFOVERVAL) { @@ -3757,10 +3537,10 @@ struct init2050_saved_values { u16 radio_52; /* PHY registers */ u16 phy_pgactl; - u16 phy_base_5A; - u16 phy_base_59; - u16 phy_base_58; - u16 phy_base_30; + u16 phy_cck_5A; + u16 phy_cck_59; + u16 phy_cck_58; + u16 phy_cck_30; u16 phy_rfover; u16 phy_rfoverval; u16 phy_analogover; @@ -3788,15 +3568,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev) sav.radio_51 = b43_radio_read16(dev, 0x51); sav.radio_52 = b43_radio_read16(dev, 0x52); sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A)); - sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59)); - sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58)); + sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); + sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); if (phy->type == B43_PHYTYPE_B) { - sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); sav.reg_3EC = b43_read16(dev, 0x3EC); - b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF); + b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); b43_write16(dev, 0x3EC, 0x3F3F); } else if (phy->gmode || phy->rev >= 2) { sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); @@ -3847,8 +3627,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_write16(dev, 0x03E6, 0x0122); } else { if (phy->analog >= 2) { - b43_phy_write(dev, B43_PHY_BASE(0x03), - (b43_phy_read(dev, B43_PHY_BASE(0x03)) + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) & 0xFFBF) | 0x40); } b43_write16(dev, B43_MMIO_CHANNEL_EXT, @@ -3865,7 +3645,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) LPD(0, 1, 1))); } b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, @@ -3881,12 +3661,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | 0x0009); } - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3912,7 +3692,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); udelay(20); tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3923,7 +3703,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) } udelay(10); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); tmp1++; tmp1 >>= 9; @@ -3932,9 +3712,9 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x78, radio78); udelay(10); for (j = 0; j < 16; j++) { - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3963,7 +3743,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); udelay(10); tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3984,16 +3764,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x51, sav.radio_51); b43_radio_write16(dev, 0x52, sav.radio_52); b43_radio_write16(dev, 0x43, sav.radio_43); - b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A); - b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59); - b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58); + b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); + b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); + b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); b43_write16(dev, 0x3E6, sav.reg_3E6); if (phy->analog != 0) b43_write16(dev, 0x3F4, sav.reg_3F4); b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); b43_synth_pu_workaround(dev, phy->channel); if (phy->type == B43_PHYTYPE_B) { - b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30); + b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); b43_write16(dev, 0x3EC, sav.reg_3EC); } else if (phy->gmode) { b43_write16(dev, B43_MMIO_PHY_RADIO, @@ -4103,7 +3883,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev, struct b43_phy *phy = &dev->phy; u16 r8, tmp; u16 freq; - u16 channelcookie; + u16 channelcookie, savedcookie; + int err = 0; if (channel == 0xFF) { switch (phy->type) { @@ -4114,6 +3895,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev, case B43_PHYTYPE_G: channel = B43_DEFAULT_CHANNEL_BG; break; + case B43_PHYTYPE_N: + //FIXME check if we are on 2.4GHz or 5GHz and set a default channel. + channel = 1; + break; default: B43_WARN_ON(1); } @@ -4123,13 +3908,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev, * firmware from sending ghost packets. */ channelcookie = channel; - if (phy->type == B43_PHYTYPE_A) + if (0 /*FIXME on 5Ghz */) channelcookie |= 0x100; + //FIXME set 40Mhz flag if required + savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); - if (phy->type == B43_PHYTYPE_A) { - if (channel > 200) - return -EINVAL; + switch (phy->type) { + case B43_PHYTYPE_A: + if (channel > 200) { + err = -EINVAL; + goto out; + } freq = channel2freq_a(channel); r8 = b43_radio_read16(dev, 0x0008); @@ -4176,9 +3966,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_radio_set_tx_iq(dev); //TODO: TSSI2dbm workaround b43_phy_xmitpower(dev); //FIXME correct? - } else { - if ((channel < 1) || (channel > 14)) - return -EINVAL; + break; + case B43_PHYTYPE_G: + if ((channel < 1) || (channel > 14)) { + err = -EINVAL; + goto out; + } if (synthetic_pu_workaround) b43_synth_pu_workaround(dev, channel); @@ -4186,7 +3979,7 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); if (channel == 14) { - if (dev->dev->bus->sprom.r1.country_code == + if (dev->dev->bus->sprom.country_code == SSB_SPROM1CCODE_JAPAN) b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACPR); @@ -4201,110 +3994,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_read16(dev, B43_MMIO_CHANNEL_EXT) & 0xF7BF); } + break; + case B43_PHYTYPE_N: + err = b43_nphy_selectchannel(dev, channel); + if (err) + goto out; + break; + default: + B43_WARN_ON(1); } phy->channel = channel; /* Wait for the radio to tune to the channel and stabilize. */ msleep(8); - - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ -static u16 b43_get_txgain_base_band(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 54) - ret = 2; - else if (txpower >= 49) - ret = 4; - else if (txpower >= 44) - ret = 5; - else - ret = 6; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ -static u16 b43_get_txgain_freq_power_amp(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 32) - ret = 0; - else if (txpower >= 25) - ret = 1; - else if (txpower >= 20) - ret = 2; - else if (txpower >= 12) - ret = 3; - else - ret = 4; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ -static u16 b43_get_txgain_dac(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 54) - ret = txpower - 53; - else if (txpower >= 49) - ret = txpower - 42; - else if (txpower >= 44) - ret = txpower - 37; - else if (txpower >= 32) - ret = txpower - 32; - else if (txpower >= 25) - ret = txpower - 20; - else if (txpower >= 20) - ret = txpower - 13; - else if (txpower >= 12) - ret = txpower - 8; - else - ret = txpower; - - return ret; -} - -static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower) -{ - struct b43_phy *phy = &dev->phy; - u16 pamp, base, dac, t; - - txpower = limit_value(txpower, 0, 63); - - pamp = b43_get_txgain_freq_power_amp(txpower); - pamp <<= 5; - pamp &= 0x00E0; - b43_phy_write(dev, 0x0019, pamp); - - base = b43_get_txgain_base_band(txpower); - base &= 0x000F; - b43_phy_write(dev, 0x0017, base | 0x0020); - - t = b43_ofdmtab_read16(dev, 0x3000, 1); - t &= 0x0007; - - dac = b43_get_txgain_dac(txpower); - dac <<= 3; - dac |= t; - - b43_ofdmtab_write16(dev, 0x3000, 1, dac); - - phy->txpwr_offset = txpower; - - //TODO: FuncPlaceholder (Adjust BB loft cancel) +out: + if (err) { + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_CHAN, savedcookie); + } + return err; } void b43_radio_turn_on(struct b43_wldev *dev) @@ -4344,6 +4052,9 @@ void b43_radio_turn_on(struct b43_wldev *dev) err |= b43_radio_selectchannel(dev, channel, 0); B43_WARN_ON(err); break; + case B43_PHYTYPE_N: + b43_nphy_radio_turn_on(dev); + break; default: B43_WARN_ON(1); } @@ -4357,13 +4068,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) if (!phy->radio_on && !force) return; - if (phy->type == B43_PHYTYPE_A) { + switch (phy->type) { + case B43_PHYTYPE_N: + b43_nphy_radio_turn_off(dev); + break; + case B43_PHYTYPE_A: b43_radio_write16(dev, 0x0004, 0x00FF); b43_radio_write16(dev, 0x0005, 0x00FB); b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); - } - if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { + break; + case B43_PHYTYPE_G: { u16 rfover, rfoverval; rfover = b43_phy_read(dev, B43_PHY_RFOVER); @@ -4375,7 +4090,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) } b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); - } else - b43_phy_write(dev, 0x0015, 0xAA00); + break; + } + default: + B43_WARN_ON(1); + } phy->radio_on = 0; } diff --git a/package/b43/src/phy.h b/package/b43/src/phy.h index c64d74504f..6d165d8221 100644 --- a/package/b43/src/phy.h +++ b/package/b43/src/phy.h @@ -9,14 +9,21 @@ struct b43_phy; /*** PHY Registers ***/ /* Routing */ -#define B43_PHYROUTE_OFDM_GPHY 0x400 -#define B43_PHYROUTE_EXT_GPHY 0x800 - -/* Base registers. */ -#define B43_PHY_BASE(reg) (reg) -/* OFDM (A) registers of a G-PHY */ +#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ +#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ +#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ +#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ +#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ + +/* CCK (B-PHY) registers. */ +#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY registers. */ +#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY BMODE registers. */ +#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) +/* OFDM (A-PHY) registers. */ #define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) -/* Extended G-PHY registers */ +/* Extended G-PHY registers. */ #define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) /* OFDM (A) PHY Registers */ @@ -25,10 +32,13 @@ struct b43_phy; #define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ #define B43_PHY_BBANDCFG_RXANT_SHIFT 7 #define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ -#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ #define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ #define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ #define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_CRS0_EN 0x4000 +#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) #define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ #define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ #define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ @@ -37,6 +47,7 @@ struct b43_phy; #define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ #define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ #define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ #define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ #define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ #define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ @@ -44,6 +55,9 @@ struct b43_phy; #define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ #define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ #define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ +#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) +#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ #define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ #define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ #define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ @@ -54,33 +68,35 @@ struct b43_phy; #define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) #define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) #define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ +#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ #define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ #define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) #define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) #define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) #define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ #define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ -#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ -#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ +#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ #define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ #define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ #define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ /* CCK (B) PHY Registers */ -#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */ -#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */ -#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */ +#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ #define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ #define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ #define B43_PHY_PGACTL_UNKNOWN 0xEFA0 -#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */ -#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */ -#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */ -#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */ -#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35) -#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */ -#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */ -#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */ +#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) +#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ /* Extended G-PHY Registers */ #define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ @@ -125,13 +141,14 @@ struct b43_phy; #define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) #define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) #define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) -//TODO +#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename +#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename #define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) #define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) -//TODO +#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename #define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) -#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename -#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) #define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) #define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) #define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) @@ -163,6 +180,8 @@ enum { B43_ANTENNA1, /* Antenna 0 */ B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + B43_ANTENNA2, + B43_ANTENNA3 = 8, B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, @@ -182,21 +201,21 @@ enum { #define B43_PHYVER_TYPE_SHIFT 8 #define B43_PHYVER_VERSION 0x00FF -void b43_raw_phy_lock(struct b43_wldev *dev); -#define b43_phy_lock(dev, flags) \ - do { \ - local_irq_save(flags); \ - b43_raw_phy_lock(dev); \ - } while (0) -void b43_raw_phy_unlock(struct b43_wldev *dev); -#define b43_phy_unlock(dev, flags) \ - do { \ - b43_raw_phy_unlock(dev); \ - local_irq_restore(flags); \ - } while (0) +void b43_phy_lock(struct b43_wldev *dev); +void b43_phy_unlock(struct b43_wldev *dev); + +/* Read a value from a PHY register */ u16 b43_phy_read(struct b43_wldev *dev, u16 offset); +/* Write a value to a PHY register */ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); +/* Mask a PHY register with a mask */ +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); +/* OR a PHY register with a bitmap */ +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); +/* Mask and OR a PHY register with a mask and bitmap */ +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); @@ -260,8 +279,18 @@ extern const u8 b43_radio_channel_codes_bg[]; void b43_radio_lock(struct b43_wldev *dev); void b43_radio_unlock(struct b43_wldev *dev); + +/* Read a value from a 16bit radio register */ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); +/* Write a value to a 16bit radio register */ void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); +/* Mask a 16bit radio register with a mask */ +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); +/* OR a 16bit radio register with a bitmap */ +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); +/* Mask and OR a PHY register with a mask and bitmap */ +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + u16 b43_radio_init2050(struct b43_wldev *dev); void b43_radio_init2060(struct b43_wldev *dev); diff --git a/package/b43/src/pio.c b/package/b43/src/pio.c deleted file mode 100644 index 67752a28eb..0000000000 --- a/package/b43/src/pio.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - - Broadcom B43 wireless driver - - PIO Transmission - - Copyright (c) 2005 Michael Buesch <mb@bu3sch.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "b43.h" -#include "pio.h" -#include "main.h" -#include "xmit.h" - -#include <linux/delay.h> - -static void tx_start(struct b43_pioqueue *queue) -{ - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT); -} - -static void tx_octet(struct b43_pioqueue *queue, u8 octet) -{ - if (queue->need_workarounds) { - b43_pio_write(queue, B43_PIO_TXDATA, octet); - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); - } else { - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); - b43_pio_write(queue, B43_PIO_TXDATA, octet); - } -} - -static u16 tx_get_next_word(const u8 * txhdr, - const u8 * packet, - size_t txhdr_size, unsigned int *pos) -{ - const u8 *source; - unsigned int i = *pos; - u16 ret; - - if (i < txhdr_size) { - source = txhdr; - } else { - source = packet; - i -= txhdr_size; - } - ret = le16_to_cpu(*((__le16 *)(source + i))); - *pos += 2; - - return ret; -} - -static void tx_data(struct b43_pioqueue *queue, - u8 * txhdr, const u8 * packet, unsigned int octets) -{ - u16 data; - unsigned int i = 0; - - if (queue->need_workarounds) { - data = tx_get_next_word(txhdr, packet, - sizeof(struct b43_txhdr_fw4), &i); - b43_pio_write(queue, B43_PIO_TXDATA, data); - } - b43_pio_write(queue, B43_PIO_TXCTL, - B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI); - while (i < octets - 1) { - data = tx_get_next_word(txhdr, packet, - sizeof(struct b43_txhdr_fw4), &i); - b43_pio_write(queue, B43_PIO_TXDATA, data); - } - if (octets % 2) - tx_octet(queue, - packet[octets - sizeof(struct b43_txhdr_fw4) - 1]); -} - -static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb) -{ - if (queue->need_workarounds) { - b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]); - b43_pio_write(queue, B43_PIO_TXCTL, - B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE); - } else { - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE); - } -} - -static u16 generate_cookie(struct b43_pioqueue *queue, - struct b43_pio_txpacket *packet) -{ - u16 cookie = 0x0000; - u16 packetindex; - - /* We use the upper 4 bits for the PIO - * controller ID and the lower 12 bits - * for the packet index (in the cache). - */ - switch (queue->mmio_base) { - case B43_MMIO_PIO1_BASE: - break; - case B43_MMIO_PIO2_BASE: - cookie = 0x1000; - break; - case B43_MMIO_PIO3_BASE: - cookie = 0x2000; - break; - case B43_MMIO_PIO4_BASE: - cookie = 0x3000; - break; - default: - B43_WARN_ON(1); - } - packetindex = packet->index; - B43_WARN_ON(packetindex & ~0x0FFF); - cookie |= (u16) packetindex; - - return cookie; -} - -static -struct b43_pioqueue *parse_cookie(struct b43_wldev *dev, - u16 cookie, struct b43_pio_txpacket **packet) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue = NULL; - int packetindex; - - switch (cookie & 0xF000) { - case 0x0000: - queue = pio->queue0; - break; - case 0x1000: - queue = pio->queue1; - break; - case 0x2000: - queue = pio->queue2; - break; - case 0x3000: - queue = pio->queue3; - break; - default: - B43_WARN_ON(1); - } - packetindex = (cookie & 0x0FFF); - B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS)); - *packet = &(queue->tx_packets_cache[packetindex]); - - return queue; -} - -union txhdr_union { - struct b43_txhdr_fw4 txhdr_fw4; -}; - -static void pio_tx_write_fragment(struct b43_pioqueue *queue, - struct sk_buff *skb, - struct b43_pio_txpacket *packet, - size_t txhdr_size) -{ - union txhdr_union txhdr_data; - u8 *txhdr = NULL; - unsigned int octets; - - txhdr = (u8 *) (&txhdr_data.txhdr_fw4); - - B43_WARN_ON(skb_shinfo(skb)->nr_frags); - b43_generate_txhdr(queue->dev, - txhdr, skb->data, skb->len, - &packet->txstat.control, - generate_cookie(queue, packet)); - - tx_start(queue); - octets = skb->len + txhdr_size; - if (queue->need_workarounds) - octets--; - tx_data(queue, txhdr, (u8 *) skb->data, octets); - tx_complete(queue, skb); -} - -static void free_txpacket(struct b43_pio_txpacket *packet) -{ - struct b43_pioqueue *queue = packet->queue; - - if (packet->skb) - dev_kfree_skb_any(packet->skb); - list_move(&packet->list, &queue->txfree); - queue->nr_txfree++; -} - -static int pio_tx_packet(struct b43_pio_txpacket *packet) -{ - struct b43_pioqueue *queue = packet->queue; - struct sk_buff *skb = packet->skb; - u16 octets; - - octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4); - if (queue->tx_devq_size < octets) { - b43warn(queue->dev->wl, "PIO queue too small. " - "Dropping packet.\n"); - /* Drop it silently (return success) */ - free_txpacket(packet); - return 0; - } - B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS); - B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); - /* Check if there is sufficient free space on the device - * TX queue. If not, return and let the TX tasklet - * retry later. - */ - if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS) - return -EBUSY; - if (queue->tx_devq_used + octets > queue->tx_devq_size) - return -EBUSY; - /* Now poke the device. */ - pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4)); - - /* Account for the packet size. - * (We must not overflow the device TX queue) - */ - queue->tx_devq_packets++; - queue->tx_devq_used += octets; - - /* Transmission started, everything ok, move the - * packet to the txrunning list. - */ - list_move_tail(&packet->list, &queue->txrunning); - - return 0; -} - -static void tx_tasklet(unsigned long d) -{ - struct b43_pioqueue *queue = (struct b43_pioqueue *)d; - struct b43_wldev *dev = queue->dev; - unsigned long flags; - struct b43_pio_txpacket *packet, *tmp_packet; - int err; - u16 txctl; - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - if (queue->tx_frozen) - goto out_unlock; - txctl = b43_pio_read(queue, B43_PIO_TXCTL); - if (txctl & B43_PIO_TXCTL_SUSPEND) - goto out_unlock; - - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { - /* Try to transmit the packet. This can fail, if - * the device queue is full. In case of failure, the - * packet is left in the txqueue. - * If transmission succeed, the packet is moved to txrunning. - * If it is impossible to transmit the packet, it - * is dropped. - */ - err = pio_tx_packet(packet); - if (err) - break; - } - out_unlock: - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); -} - -static void setup_txqueues(struct b43_pioqueue *queue) -{ - struct b43_pio_txpacket *packet; - int i; - - queue->nr_txfree = B43_PIO_MAXTXPACKETS; - for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) { - packet = &(queue->tx_packets_cache[i]); - - packet->queue = queue; - INIT_LIST_HEAD(&packet->list); - packet->index = i; - - list_add(&packet->list, &queue->txfree); - } -} - -static -struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev, - u16 pio_mmio_base) -{ - struct b43_pioqueue *queue; - u16 qsize; - - queue = kzalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) - goto out; - - queue->dev = dev; - queue->mmio_base = pio_mmio_base; - queue->need_workarounds = (dev->dev->id.revision < 3); - - INIT_LIST_HEAD(&queue->txfree); - INIT_LIST_HEAD(&queue->txqueue); - INIT_LIST_HEAD(&queue->txrunning); - tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); - - b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) - & ~B43_MACCTL_BE); - - qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE); - if (qsize == 0) { - b43err(dev->wl, "This card does not support PIO " - "operation mode. Please use DMA mode " - "(module parameter pio=0).\n"); - goto err_freequeue; - } - if (qsize <= B43_PIO_TXQADJUST) { - b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize); - goto err_freequeue; - } - qsize -= B43_PIO_TXQADJUST; - queue->tx_devq_size = qsize; - - setup_txqueues(queue); - - out: - return queue; - - err_freequeue: - kfree(queue); - queue = NULL; - goto out; -} - -static void cancel_transfers(struct b43_pioqueue *queue) -{ - struct b43_pio_txpacket *packet, *tmp_packet; - - tasklet_disable(&queue->txtask); - - list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) - free_txpacket(packet); - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) - free_txpacket(packet); -} - -static void b43_destroy_pioqueue(struct b43_pioqueue *queue) -{ - if (!queue) - return; - - cancel_transfers(queue); - kfree(queue); -} - -void b43_pio_free(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - if (!b43_using_pio(dev)) - return; - pio = &dev->pio; - - b43_destroy_pioqueue(pio->queue3); - pio->queue3 = NULL; - b43_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; - b43_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; - b43_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; -} - -int b43_pio_init(struct b43_wldev *dev) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue; - int err = -ENOMEM; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE); - if (!queue) - goto out; - pio->queue0 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE); - if (!queue) - goto err_destroy0; - pio->queue1 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE); - if (!queue) - goto err_destroy1; - pio->queue2 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE); - if (!queue) - goto err_destroy2; - pio->queue3 = queue; - - if (dev->dev->id.revision < 3) - dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND; - - b43dbg(dev->wl, "PIO initialized\n"); - err = 0; - out: - return err; - - err_destroy2: - b43_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; - err_destroy1: - b43_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; - err_destroy0: - b43_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; - goto out; -} - -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct b43_pioqueue *queue = dev->pio.queue1; - struct b43_pio_txpacket *packet; - - B43_WARN_ON(queue->tx_suspended); - B43_WARN_ON(list_empty(&queue->txfree)); - - packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list); - packet->skb = skb; - - memset(&packet->txstat, 0, sizeof(packet->txstat)); - memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); - - list_move_tail(&packet->list, &queue->txqueue); - queue->nr_txfree--; - queue->nr_tx_packets++; - B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS); - - tasklet_schedule(&queue->txtask); - - return 0; -} - -void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ - struct b43_pioqueue *queue; - struct b43_pio_txpacket *packet; - - queue = parse_cookie(dev, status->cookie, &packet); - if (B43_WARN_ON(!queue)) - return; - - queue->tx_devq_packets--; - queue->tx_devq_used -= - (packet->skb->len + sizeof(struct b43_txhdr_fw4)); - - if (status->acked) { - packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; - } else { - if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK)) - packet->txstat.excessive_retries = 1; - } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - packet->txstat.retry_count = 0; - } else - packet->txstat.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, - &(packet->txstat)); - packet->skb = NULL; - - free_txpacket(packet); - /* If there are packets on the txqueue, poke the tasklet - * to transmit them. - */ - if (!list_empty(&queue->txqueue)) - tasklet_schedule(&queue->txtask); -} - -void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue; - struct ieee80211_tx_queue_stats_data *data; - - queue = pio->queue1; - data = &(stats->data[0]); - data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree; - data->limit = B43_PIO_MAXTXPACKETS; - data->count = queue->nr_tx_packets; -} - -static void pio_rx_error(struct b43_pioqueue *queue, - int clear_buffers, const char *error) -{ - int i; - - b43err(queue->dev->wl, "PIO RX error: %s\n", error); - b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY); - if (clear_buffers) { - B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE); - for (i = 0; i < 15; i++) { - /* Dummy read. */ - b43_pio_read(queue, B43_PIO_RXDATA); - } - } -} - -void b43_pio_rx(struct b43_pioqueue *queue) -{ - __le16 preamble[21] = { 0 }; - struct b43_rxhdr_fw4 *rxhdr; - u16 tmp, len; - u32 macstat; - int i, preamble_readwords; - struct sk_buff *skb; - - tmp = b43_pio_read(queue, B43_PIO_RXCTL); - if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE)) - return; - b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE); - - for (i = 0; i < 10; i++) { - tmp = b43_pio_read(queue, B43_PIO_RXCTL); - if (tmp & B43_PIO_RXCTL_READY) - goto data_ready; - udelay(10); - } - b43dbg(queue->dev->wl, "PIO RX timed out\n"); - return; -data_ready: - - len = b43_pio_read(queue, B43_PIO_RXDATA); - if (unlikely(len > 0x700)) { - pio_rx_error(queue, 0, "len > 0x700"); - return; - } - if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) { - pio_rx_error(queue, 0, "len == 0"); - return; - } - preamble[0] = cpu_to_le16(len); - if (queue->mmio_base == B43_MMIO_PIO4_BASE) - preamble_readwords = 14 / sizeof(u16); - else - preamble_readwords = 18 / sizeof(u16); - for (i = 0; i < preamble_readwords; i++) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - preamble[i + 1] = cpu_to_le16(tmp); - } - rxhdr = (struct b43_rxhdr_fw4 *)preamble; - macstat = le32_to_cpu(rxhdr->mac_status); - if (macstat & B43_RX_MAC_FCSERR) { - pio_rx_error(queue, - (queue->mmio_base == B43_MMIO_PIO1_BASE), - "Frame FCS error"); - return; - } - if (queue->mmio_base == B43_MMIO_PIO4_BASE) { - /* We received an xmit status. */ - struct b43_hwtxstatus *hw; - - hw = (struct b43_hwtxstatus *)(preamble + 1); - b43_handle_hwtxstatus(queue->dev, hw); - - return; - } - - skb = dev_alloc_skb(len); - if (unlikely(!skb)) { - pio_rx_error(queue, 1, "OOM"); - return; - } - skb_put(skb, len); - for (i = 0; i < len - 1; i += 2) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); - } - if (len % 2) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - skb->data[len - 1] = (tmp & 0x00FF); -/* The specs say the following is required, but - * it is wrong and corrupts the PLCP. If we don't do - * this, the PLCP seems to be correct. So ifdef it out for now. - */ -#if 0 - if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME) - skb->data[2] = (tmp & 0xFF00) >> 8; - else - skb->data[0] = (tmp & 0xFF00) >> 8; -#endif - } - b43_rx(queue->dev, skb, rxhdr); -} - -void b43_pio_tx_suspend(struct b43_pioqueue *queue) -{ - b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE); - b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) - | B43_PIO_TXCTL_SUSPEND); -} - -void b43_pio_tx_resume(struct b43_pioqueue *queue) -{ - b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) - & ~B43_PIO_TXCTL_SUSPEND); - b43_power_saving_ctl_bits(queue->dev, 0); - tasklet_schedule(&queue->txtask); -} - -void b43_pio_freeze_txqueues(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - B43_WARN_ON(!b43_using_pio(dev)); - pio = &dev->pio; - pio->queue0->tx_frozen = 1; - pio->queue1->tx_frozen = 1; - pio->queue2->tx_frozen = 1; - pio->queue3->tx_frozen = 1; -} - -void b43_pio_thaw_txqueues(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - B43_WARN_ON(!b43_using_pio(dev)); - pio = &dev->pio; - pio->queue0->tx_frozen = 0; - pio->queue1->tx_frozen = 0; - pio->queue2->tx_frozen = 0; - pio->queue3->tx_frozen = 0; - if (!list_empty(&pio->queue0->txqueue)) - tasklet_schedule(&pio->queue0->txtask); - if (!list_empty(&pio->queue1->txqueue)) - tasklet_schedule(&pio->queue1->txtask); - if (!list_empty(&pio->queue2->txqueue)) - tasklet_schedule(&pio->queue2->txtask); - if (!list_empty(&pio->queue3->txqueue)) - tasklet_schedule(&pio->queue3->txtask); -} diff --git a/package/b43/src/pio.h b/package/b43/src/pio.h deleted file mode 100644 index 3488f2447b..0000000000 --- a/package/b43/src/pio.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef B43_PIO_H_ -#define B43_PIO_H_ - -#include "b43.h" - -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/skbuff.h> - -#define B43_PIO_TXCTL 0x00 -#define B43_PIO_TXDATA 0x02 -#define B43_PIO_TXQBUFSIZE 0x04 -#define B43_PIO_RXCTL 0x08 -#define B43_PIO_RXDATA 0x0A - -#define B43_PIO_TXCTL_WRITELO (1 << 0) -#define B43_PIO_TXCTL_WRITEHI (1 << 1) -#define B43_PIO_TXCTL_COMPLETE (1 << 2) -#define B43_PIO_TXCTL_INIT (1 << 3) -#define B43_PIO_TXCTL_SUSPEND (1 << 7) - -#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0) -#define B43_PIO_RXCTL_READY (1 << 1) - -/* PIO constants */ -#define B43_PIO_MAXTXDEVQPACKETS 31 -#define B43_PIO_TXQADJUST 80 - -/* PIO tuning knobs */ -#define B43_PIO_MAXTXPACKETS 256 - -#ifdef CONFIG_B43_PIO - -struct b43_pioqueue; -struct b43_xmitstatus; - -struct b43_pio_txpacket { - struct b43_pioqueue *queue; - struct sk_buff *skb; - struct ieee80211_tx_status txstat; - struct list_head list; - u16 index; /* Index in the tx_packets_cache */ -}; - -struct b43_pioqueue { - struct b43_wldev *dev; - u16 mmio_base; - - bool tx_suspended; - bool tx_frozen; - bool need_workarounds; /* Workarounds needed for core.rev < 3 */ - - /* Adjusted size of the device internal TX buffer. */ - u16 tx_devq_size; - /* Used octets of the device internal TX buffer. */ - u16 tx_devq_used; - /* Used packet slots in the device internal TX buffer. */ - u8 tx_devq_packets; - /* Packets from the txfree list can - * be taken on incoming TX requests. - */ - struct list_head txfree; - unsigned int nr_txfree; - /* Packets on the txqueue are queued, - * but not completely written to the chip, yet. - */ - struct list_head txqueue; - /* Packets on the txrunning queue are completely - * posted to the device. We are waiting for the txstatus. - */ - struct list_head txrunning; - /* Total number or packets sent. - * (This counter can obviously wrap). - */ - unsigned int nr_tx_packets; - struct tasklet_struct txtask; - struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS]; -}; - -static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset) -{ - return b43_read16(queue->dev, queue->mmio_base + offset); -} - -static inline - void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value) -{ - b43_write16(queue->dev, queue->mmio_base + offset, value); - mmiowb(); -} - -int b43_pio_init(struct b43_wldev *dev); -void b43_pio_free(struct b43_wldev *dev); - -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); -void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status); -void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats); -void b43_pio_rx(struct b43_pioqueue *queue); - -/* Suspend TX queue in hardware. */ -void b43_pio_tx_suspend(struct b43_pioqueue *queue); -void b43_pio_tx_resume(struct b43_pioqueue *queue); -/* Suspend (freeze) the TX tasklet (software level). */ -void b43_pio_freeze_txqueues(struct b43_wldev *dev); -void b43_pio_thaw_txqueues(struct b43_wldev *dev); - -#else /* CONFIG_B43_PIO */ - -static inline int b43_pio_init(struct b43_wldev *dev) -{ - return 0; -} -static inline void b43_pio_free(struct b43_wldev *dev) -{ -} -static inline - int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - return 0; -} -static inline - void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ -} -static inline - void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ -} -static inline void b43_pio_rx(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_tx_resume(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev) -{ -} -static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev) -{ -} - -#endif /* CONFIG_B43_PIO */ -#endif /* B43_PIO_H_ */ diff --git a/package/b43/src/rfkill.c b/package/b43/src/rfkill.c index 800e0a61a7..11f53cb113 100644 --- a/package/b43/src/rfkill.c +++ b/package/b43/src/rfkill.c @@ -25,6 +25,8 @@ #include "rfkill.h" #include "b43.h" +#include <linux/kmod.h> + /* Returns TRUE, if the radio is enabled in hardware. */ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) @@ -47,32 +49,44 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) struct b43_wldev *dev = poll_dev->private; struct b43_wl *wl = dev->wl; bool enabled; + bool report_change = 0; mutex_lock(&wl->mutex); - B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); + if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { + mutex_unlock(&wl->mutex); + return; + } enabled = b43_is_hw_radio_enabled(dev); if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; + report_change = 1; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - mutex_unlock(&wl->mutex); - input_report_key(poll_dev->input, KEY_WLAN, enabled); - } else - mutex_unlock(&wl->mutex); + } + mutex_unlock(&wl->mutex); + + /* send the radio switch event to the system - note both a key press + * and a release are required */ + if (unlikely(report_change)) { + input_report_key(poll_dev->input, KEY_WLAN, 1); + input_report_key(poll_dev->input, KEY_WLAN, 0); + } } -/* Called when the RFKILL toggled in software. - * This is called without locking. */ +/* Called when the RFKILL toggled in software. */ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) { struct b43_wldev *dev = data; struct b43_wl *wl = dev->wl; - int err = 0; + int err = -EBUSY; + + if (!wl->rfkill.registered) + return 0; mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; - + err = 0; switch (state) { case RFKILL_STATE_ON: if (!dev->radio_hw_enable) { @@ -89,7 +103,6 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) b43_radio_turn_off(dev, 0); break; } - out_unlock: mutex_unlock(&wl->mutex); @@ -98,11 +111,11 @@ out_unlock: char * b43_rfkill_led_name(struct b43_wldev *dev) { - struct b43_wl *wl = dev->wl; + struct b43_rfkill *rfk = &(dev->wl->rfkill); - if (!wl->rfkill.rfkill) + if (!rfk->registered) return NULL; - return rfkill_get_led_name(wl->rfkill.rfkill); + return rfkill_get_led_name(rfk->rfkill); } void b43_rfkill_init(struct b43_wldev *dev) @@ -111,53 +124,13 @@ void b43_rfkill_init(struct b43_wldev *dev) struct b43_rfkill *rfk = &(wl->rfkill); int err; - if (rfk->rfkill) { - err = rfkill_register(rfk->rfkill); - if (err) { - b43warn(wl, "Failed to register RF-kill button\n"); - goto err_free_rfk; - } - } - if (rfk->poll_dev) { - err = input_register_polled_device(rfk->poll_dev); - if (err) { - b43warn(wl, "Failed to register RF-kill polldev\n"); - goto err_free_polldev; - } - } - - return; -err_free_rfk: - rfkill_free(rfk->rfkill); - rfk->rfkill = NULL; -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -} - -void b43_rfkill_exit(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (rfk->poll_dev) - input_unregister_polled_device(rfk->poll_dev); - if (rfk->rfkill) - rfkill_unregister(rfk->rfkill); -} - -void b43_rfkill_alloc(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - struct b43_rfkill *rfk = &(wl->rfkill); + rfk->registered = 0; + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) + goto out_error; snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); - - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) { - b43warn(wl, "Failed to allocate RF-kill button\n"); - return; - } rfk->rfkill->name = rfk->name; rfk->rfkill->state = RFKILL_STATE_ON; rfk->rfkill->data = dev; @@ -165,20 +138,64 @@ void b43_rfkill_alloc(struct b43_wldev *dev) rfk->rfkill->user_claim_unsupported = 1; rfk->poll_dev = input_allocate_polled_device(); - if (rfk->poll_dev) { - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - } else - b43warn(wl, "Failed to allocate RF-kill polldev\n"); + if (!rfk->poll_dev) { + rfkill_free(rfk->rfkill); + goto err_freed_rfk; + } + + rfk->poll_dev->private = dev; + rfk->poll_dev->poll = b43_rfkill_poll; + rfk->poll_dev->poll_interval = 1000; /* msecs */ + + rfk->poll_dev->input->name = rfk->name; + rfk->poll_dev->input->id.bustype = BUS_HOST; + rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; + rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + + err = rfkill_register(rfk->rfkill); + if (err) + goto err_free_polldev; + +#ifdef CONFIG_RFKILL_INPUT_MODULE + /* B43 RF-kill isn't useful without the rfkill-input subsystem. + * Try to load the module. */ + err = request_module("rfkill-input"); + if (err) + b43warn(wl, "Failed to load the rfkill-input module. " + "The built-in radio LED will not work.\n"); +#endif /* CONFIG_RFKILL_INPUT */ + + err = input_register_polled_device(rfk->poll_dev); + if (err) + goto err_unreg_rfk; + + rfk->registered = 1; + + return; +err_unreg_rfk: + rfkill_unregister(rfk->rfkill); +err_free_polldev: + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; +err_freed_rfk: + rfk->rfkill = NULL; +out_error: + rfk->registered = 0; + b43warn(wl, "RF-kill button init failed\n"); } -void b43_rfkill_free(struct b43_wldev *dev) +void b43_rfkill_exit(struct b43_wldev *dev) { struct b43_rfkill *rfk = &(dev->wl->rfkill); + if (!rfk->registered) + return; + rfk->registered = 0; + + input_unregister_polled_device(rfk->poll_dev); + rfkill_unregister(rfk->rfkill); input_free_polled_device(rfk->poll_dev); rfk->poll_dev = NULL; - rfkill_free(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/package/b43/src/rfkill.h b/package/b43/src/rfkill.h index 29544e8c9e..adacf936d8 100644 --- a/package/b43/src/rfkill.h +++ b/package/b43/src/rfkill.h @@ -15,14 +15,14 @@ struct b43_rfkill { struct rfkill *rfkill; /* The poll device for the RFKILL input button */ struct input_polled_dev *poll_dev; + /* Did initialization succeed? Used for freeing. */ + bool registered; /* The unique name of this rfkill switch */ - char name[32]; + char name[sizeof("b43-phy4294967295")]; }; -/* All the init functions return void, because we are not interested +/* The init function returns void, because we are not interested * in failing the b43 init process when rfkill init failed. */ -void b43_rfkill_alloc(struct b43_wldev *dev); -void b43_rfkill_free(struct b43_wldev *dev); void b43_rfkill_init(struct b43_wldev *dev); void b43_rfkill_exit(struct b43_wldev *dev); @@ -36,12 +36,6 @@ struct b43_rfkill { /* empty */ }; -static inline void b43_rfkill_alloc(struct b43_wldev *dev) -{ -} -static inline void b43_rfkill_free(struct b43_wldev *dev) -{ -} static inline void b43_rfkill_init(struct b43_wldev *dev) { } diff --git a/package/b43/src/sysfs.c b/package/b43/src/sysfs.c index f4faff6a7d..275095b8cb 100644 --- a/package/b43/src/sysfs.c +++ b/package/b43/src/sysfs.c @@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count) return ret; } -static int get_boolean(const char *buf, size_t count) -{ - if (count != 0) { - if (buf[0] == '1') - return 1; - if (buf[0] == '0') - return 0; - if (count >= 4 && memcmp(buf, "true", 4) == 0) - return 1; - if (count >= 5 && memcmp(buf, "false", 5) == 0) - return 0; - if (count >= 3 && memcmp(buf, "yes", 3) == 0) - return 1; - if (count >= 2 && memcmp(buf, "no", 2) == 0) - return 0; - if (count >= 2 && memcmp(buf, "on", 2) == 0) - return 1; - if (count >= 3 && memcmp(buf, "off", 3) == 0) - return 0; - } - return -EINVAL; -} - static ssize_t b43_attr_interfmode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, static DEVICE_ATTR(interference, 0644, b43_attr_interfmode_show, b43_attr_interfmode_store); -static ssize_t b43_attr_preamble_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - ssize_t count; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&wldev->wl->mutex); - - if (wldev->short_preamble) - count = - snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); - else - count = - snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); - - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static ssize_t b43_attr_preamble_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; - int value; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - value = get_boolean(buf, count); - if (value < 0) - return value; - mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); - - wldev->short_preamble = !!value; - - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static DEVICE_ATTR(shortpreamble, 0644, - b43_attr_preamble_show, b43_attr_preamble_store); - int b43_sysfs_register(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - int err; B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); - err = device_create_file(dev, &dev_attr_interference); - if (err) - goto out; - err = device_create_file(dev, &dev_attr_shortpreamble); - if (err) - goto err_remove_interfmode; - - out: - return err; - err_remove_interfmode: - device_remove_file(dev, &dev_attr_interference); - goto out; + return device_create_file(dev, &dev_attr_interference); } void b43_sysfs_unregister(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - device_remove_file(dev, &dev_attr_shortpreamble); device_remove_file(dev, &dev_attr_interference); } diff --git a/package/b43/src/tables.c b/package/b43/src/tables.c index 15a87183a5..3f5ea06bf1 100644 --- a/package/b43/src/tables.c +++ b/package/b43/src/tables.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = { }; const u16 b43_tab_noisea3[] = { - 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x5E5E, 0x5E5E, 0x5E5E, 0x3F48, 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, }; @@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = { 0x0000, 0x0000, 0x0000, 0x0000, }; +const u16 b43_tab_noisescalea2[] = { + 0x6767, 0x6767, 0x6767, 0x6767, /* 0 */ + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6700, 0x6767, 0x6767, + 0x6767, 0x6767, 0x6767, 0x6767, /* 16 */ + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6767, 0x0067, +}; + +const u16 b43_tab_noisescalea3[] = { + 0x2323, 0x2323, 0x2323, 0x2323, /* 0 */ + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2300, 0x2323, 0x2323, + 0x2323, 0x2323, 0x2323, 0x2323, /* 16 */ + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2323, 0x0023, +}; + const u16 b43_tab_noisescaleg1[] = { 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ 0x2F2D, 0x2A2A, 0x2527, 0x1F21, @@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = { }; const u16 b43_tab_noisescaleg2[] = { - 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7, /* 0 */ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, 0x969B, 0x9195, 0x8F8F, 0x8A8A, 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, @@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = { 0x00DE, }; +const u16 b43_tab_rssiagc1[] = { + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */ + 0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE, + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, +}; + +const u16 b43_tab_rssiagc2[] = { + 0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, +}; + static inline void assert_sizes(void) { BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor)); @@ -317,36 +359,73 @@ static inline void assert_sizes(void) BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3)); BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1)); BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != + ARRAY_SIZE(b43_tab_noisescalea2)); + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != + ARRAY_SIZE(b43_tab_noisescalea3)); + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg1)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg2)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg3)); BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1)); BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2)); + BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1)); + BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2)); } u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) { - assert_sizes(); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + } + phy->ofdmtab_addr = addr; - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); return b43_phy_read(dev, B43_PHY_OTABLEI); + + /* Some compiletime assertions... */ + assert_sizes(); } void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, u16 offset, u16 value) { - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + } + phy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); } u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) { + struct b43_phy *phy = &dev->phy; u32 ret; + u16 addr; - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + } + phy->ofdmtab_addr = addr; ret = b43_phy_read(dev, B43_PHY_OTABLEQ); ret <<= 16; ret |= b43_phy_read(dev, B43_PHY_OTABLEI); @@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value) { - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + } + phy->ofdmtab_addr = addr; + b43_phy_write(dev, B43_PHY_OTABLEI, value); b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); } diff --git a/package/b43/src/tables.h b/package/b43/src/tables.h index 64635d7b51..80e73c7cba 100644 --- a/package/b43/src/tables.h +++ b/package/b43/src/tables.h @@ -1,9 +1,9 @@ #ifndef B43_TABLES_H_ #define B43_TABLES_H_ -#define B43_TAB_ROTOR_SIZE 53 +#define B43_TAB_ROTOR_SIZE 53 extern const u32 b43_tab_rotor[]; -#define B43_TAB_RETARD_SIZE 53 +#define B43_TAB_RETARD_SIZE 53 extern const u32 b43_tab_retard[]; #define B43_TAB_FINEFREQA_SIZE 256 extern const u16 b43_tab_finefreqa[]; @@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[]; extern const u16 b43_tab_noiseg1[]; #define B43_TAB_NOISEG2_SIZE 8 extern const u16 b43_tab_noiseg2[]; -#define B43_TAB_NOISESCALEG_SIZE 27 +#define B43_TAB_NOISESCALE_SIZE 27 +extern const u16 b43_tab_noisescalea2[]; +extern const u16 b43_tab_noisescalea3[]; extern const u16 b43_tab_noisescaleg1[]; extern const u16 b43_tab_noisescaleg2[]; extern const u16 b43_tab_noisescaleg3[]; #define B43_TAB_SIGMASQR_SIZE 53 extern const u16 b43_tab_sigmasqr1[]; extern const u16 b43_tab_sigmasqr2[]; +#define B43_TAB_RSSIAGC1_SIZE 16 +extern const u16 b43_tab_rssiagc1[]; +#define B43_TAB_RSSIAGC2_SIZE 48 +extern const u16 b43_tab_rssiagc2[]; #endif /* B43_TABLES_H_ */ diff --git a/package/b43/src/tables_nphy.c b/package/b43/src/tables_nphy.c new file mode 100644 index 0000000000..2aa5755178 --- /dev/null +++ b/package/b43/src/tables_nphy.c @@ -0,0 +1,2476 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY and radio device data tables + + Copyright (c) 2008 Michael Buesch <mb@bu3sch.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables_nphy.h" +#include "phy.h" +#include "nphy.h" + + +struct b2055_inittab_entry { + /* Value to write if we use the 5GHz band. */ + u16 ghz5; + /* Value to write if we use the 2.4GHz band. */ + u16 ghz2; + /* Flags */ + u8 flags; +#define B2055_INITTAB_ENTRY_OK 0x01 +#define B2055_INITTAB_UPLOAD 0x02 +}; +#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD +#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK + +static const struct b2055_inittab_entry b2055_inittab [] = { + [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, }, + [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, }, + [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, }, + [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, }, + [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, }, + [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, + [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, }, + [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, }, + [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, }, + [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, }, + [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, + [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, }, + [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, }, + [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, }, + [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, }, + [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, }, + [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, }, + [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, }, + [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, }, + [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, }, + [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, }, + [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, }, + [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, }, + [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, }, + [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, }, + [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, }, + [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, }, + [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, +}; + + +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag) +{ + const struct b2055_inittab_entry *e; + unsigned int i; + u16 value; + + for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) { + e = &(b2055_inittab[i]); + if (!(e->flags & B2055_INITTAB_ENTRY_OK)) + continue; + if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) { + if (ghz5) + value = e->ghz5; + else + value = e->ghz2; + b43_radio_write16(dev, i, value); + } + } +} + + +#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \ + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \ + .radio_pll_ref = r0, \ + .radio_rf_pllmod0 = r1, \ + .radio_rf_pllmod1 = r2, \ + .radio_vco_captail = r3, \ + .radio_vco_cal1 = r4, \ + .radio_vco_cal2 = r5, \ + .radio_pll_lfc1 = r6, \ + .radio_pll_lfr1 = r7, \ + .radio_pll_lfc2 = r8, \ + .radio_lgbuf_cenbuf = r9, \ + .radio_lgen_tune1 = r10, \ + .radio_lgen_tune2 = r11, \ + .radio_c1_lgbuf_atune = r12, \ + .radio_c1_lgbuf_gtune = r13, \ + .radio_c1_rx_rfr1 = r14, \ + .radio_c1_tx_pgapadtn = r15, \ + .radio_c1_tx_mxbgtrim = r16, \ + .radio_c2_lgbuf_atune = r17, \ + .radio_c2_lgbuf_gtune = r18, \ + .radio_c2_rx_rfr1 = r19, \ + .radio_c2_tx_pgapadtn = r20, \ + .radio_c2_tx_mxbgtrim = r21 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_bw1a = r0, \ + .phy_bw2 = r1, \ + .phy_bw3 = r2, \ + .phy_bw4 = r3, \ + .phy_bw5 = r4, \ + .phy_bw6 = r5 + +static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = { + { .channel = 184, + .freq = 4920, /* MHz */ + .unk2 = 3280, + RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602), + }, + { .channel = 186, + .freq = 4930, /* MHz */ + .unk2 = 3287, + RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502), + }, + { .channel = 188, + .freq = 4940, /* MHz */ + .unk2 = 3293, + RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402), + }, + { .channel = 190, + .freq = 4950, /* MHz */ + .unk2 = 3300, + RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302), + }, + { .channel = 192, + .freq = 4960, /* MHz */ + .unk2 = 3307, + RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202), + }, + { .channel = 194, + .freq = 4970, /* MHz */ + .unk2 = 3313, + RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102), + }, + { .channel = 196, + .freq = 4980, /* MHz */ + .unk2 = 3320, + RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02), + }, + { .channel = 198, + .freq = 4990, /* MHz */ + .unk2 = 3327, + RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02), + }, + { .channel = 200, + .freq = 5000, /* MHz */ + .unk2 = 3333, + RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02), + }, + { .channel = 202, + .freq = 5010, /* MHz */ + .unk2 = 3340, + RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02), + }, + { .channel = 204, + .freq = 5020, /* MHz */ + .unk2 = 3347, + RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02), + }, + { .channel = 206, + .freq = 5030, /* MHz */ + .unk2 = 3353, + RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02), + }, + { .channel = 208, + .freq = 5040, /* MHz */ + .unk2 = 3360, + RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902), + }, + { .channel = 210, + .freq = 5050, /* MHz */ + .unk2 = 3367, + RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802), + }, + { .channel = 212, + .freq = 5060, /* MHz */ + .unk2 = 3373, + RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702), + }, + { .channel = 214, + .freq = 5070, /* MHz */ + .unk2 = 3380, + RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602), + }, + { .channel = 216, + .freq = 5080, /* MHz */ + .unk2 = 3387, + RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502), + }, + { .channel = 218, + .freq = 5090, /* MHz */ + .unk2 = 3393, + RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402), + }, + { .channel = 220, + .freq = 5100, /* MHz */ + .unk2 = 3400, + RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302), + }, + { .channel = 222, + .freq = 5110, /* MHz */ + .unk2 = 3407, + RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202), + }, + { .channel = 224, + .freq = 5120, /* MHz */ + .unk2 = 3413, + RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102), + }, + { .channel = 226, + .freq = 5130, /* MHz */ + .unk2 = 3420, + RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002), + }, + { .channel = 228, + .freq = 5140, /* MHz */ + .unk2 = 3427, + RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, + 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B), + PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01), + }, + { .channel = 32, + .freq = 5160, /* MHz */ + .unk2 = 3440, + RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01), + }, + { .channel = 34, + .freq = 5170, /* MHz */ + .unk2 = 3447, + RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01), + }, + { .channel = 36, + .freq = 5180, /* MHz */ + .unk2 = 3453, + RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01), + }, + { .channel = 38, + .freq = 5190, /* MHz */ + .unk2 = 3460, + RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01), + }, + { .channel = 40, + .freq = 5200, /* MHz */ + .unk2 = 3467, + RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901), + }, + { .channel = 42, + .freq = 5210, /* MHz */ + .unk2 = 3473, + RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801), + }, + { .channel = 44, + .freq = 5220, /* MHz */ + .unk2 = 3480, + RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701), + }, + { .channel = 46, + .freq = 5230, /* MHz */ + .unk2 = 3487, + RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601), + }, + { .channel = 48, + .freq = 5240, /* MHz */ + .unk2 = 3493, + RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501), + }, + { .channel = 50, + .freq = 5250, /* MHz */ + .unk2 = 3500, + RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401), + }, + { .channel = 52, + .freq = 5260, /* MHz */ + .unk2 = 3507, + RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301), + }, + { .channel = 54, + .freq = 5270, /* MHz */ + .unk2 = 3513, + RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201), + }, + { .channel = 56, + .freq = 5280, /* MHz */ + .unk2 = 3520, + RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101), + }, + { .channel = 58, + .freq = 5290, /* MHz */ + .unk2 = 3527, + RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001), + }, + { .channel = 60, + .freq = 5300, /* MHz */ + .unk2 = 3533, + RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001), + }, + { .channel = 62, + .freq = 5310, /* MHz */ + .unk2 = 3540, + RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01), + }, + { .channel = 64, + .freq = 5320, /* MHz */ + .unk2 = 3547, + RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01), + }, + { .channel = 66, + .freq = 5330, /* MHz */ + .unk2 = 3553, + RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01), + }, + { .channel = 68, + .freq = 5340, /* MHz */ + .unk2 = 3560, + RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01), + }, + { .channel = 70, + .freq = 5350, /* MHz */ + .unk2 = 3567, + RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01), + }, + { .channel = 72, + .freq = 5360, /* MHz */ + .unk2 = 3573, + RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01), + }, + { .channel = 74, + .freq = 5370, /* MHz */ + .unk2 = 3580, + RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901), + }, + { .channel = 76, + .freq = 5380, /* MHz */ + .unk2 = 3587, + RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801), + }, + { .channel = 78, + .freq = 5390, /* MHz */ + .unk2 = 3593, + RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701), + }, + { .channel = 80, + .freq = 5400, /* MHz */ + .unk2 = 3600, + RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601), + }, + { .channel = 82, + .freq = 5410, /* MHz */ + .unk2 = 3607, + RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501), + }, + { .channel = 84, + .freq = 5420, /* MHz */ + .unk2 = 3613, + RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501), + }, + { .channel = 86, + .freq = 5430, /* MHz */ + .unk2 = 3620, + RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401), + }, + { .channel = 88, + .freq = 5440, /* MHz */ + .unk2 = 3627, + RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301), + }, + { .channel = 90, + .freq = 5450, /* MHz */ + .unk2 = 3633, + RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201), + }, + { .channel = 92, + .freq = 5460, /* MHz */ + .unk2 = 3640, + RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101), + }, + { .channel = 94, + .freq = 5470, /* MHz */ + .unk2 = 3647, + RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001), + }, + { .channel = 96, + .freq = 5480, /* MHz */ + .unk2 = 3653, + RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01), + }, + { .channel = 98, + .freq = 5490, /* MHz */ + .unk2 = 3660, + RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01), + }, + { .channel = 100, + .freq = 5500, /* MHz */ + .unk2 = 3667, + RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01), + }, + { .channel = 102, + .freq = 5510, /* MHz */ + .unk2 = 3673, + RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01), + }, + { .channel = 104, + .freq = 5520, /* MHz */ + .unk2 = 3680, + RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01), + }, + { .channel = 106, + .freq = 5530, /* MHz */ + .unk2 = 3687, + RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01), + }, + { .channel = 108, + .freq = 5540, /* MHz */ + .unk2 = 3693, + RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01), + }, + { .channel = 110, + .freq = 5550, /* MHz */ + .unk2 = 3700, + RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901), + }, + { .channel = 112, + .freq = 5560, /* MHz */ + .unk2 = 3707, + RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801), + }, + { .channel = 114, + .freq = 5570, /* MHz */ + .unk2 = 3713, + RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701), + }, + { .channel = 116, + .freq = 5580, /* MHz */ + .unk2 = 3720, + RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701), + }, + { .channel = 118, + .freq = 5590, /* MHz */ + .unk2 = 3727, + RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601), + }, + { .channel = 120, + .freq = 5600, /* MHz */ + .unk2 = 3733, + RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501), + }, + { .channel = 122, + .freq = 5610, /* MHz */ + .unk2 = 3740, + RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401), + }, + { .channel = 124, + .freq = 5620, /* MHz */ + .unk2 = 3747, + RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301), + }, + { .channel = 126, + .freq = 5630, /* MHz */ + .unk2 = 3753, + RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201), + }, + { .channel = 128, + .freq = 5640, /* MHz */ + .unk2 = 3760, + RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201), + }, + { .channel = 130, + .freq = 5650, /* MHz */ + .unk2 = 3767, + RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101), + }, + { .channel = 132, + .freq = 5660, /* MHz */ + .unk2 = 3773, + RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001), + }, + { .channel = 134, + .freq = 5670, /* MHz */ + .unk2 = 3780, + RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01), + }, + { .channel = 136, + .freq = 5680, /* MHz */ + .unk2 = 3787, + RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01), + }, + { .channel = 138, + .freq = 5690, /* MHz */ + .unk2 = 3793, + RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01), + }, + { .channel = 140, + .freq = 5700, /* MHz */ + .unk2 = 3800, + RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01), + }, + { .channel = 142, + .freq = 5710, /* MHz */ + .unk2 = 3807, + RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01), + }, + { .channel = 144, + .freq = 5720, /* MHz */ + .unk2 = 3813, + RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 145, + .freq = 5725, /* MHz */ + .unk2 = 3817, + RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 146, + .freq = 5730, /* MHz */ + .unk2 = 3820, + RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01), + }, + { .channel = 147, + .freq = 5735, /* MHz */ + .unk2 = 3823, + RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01), + }, + { .channel = 148, + .freq = 5740, /* MHz */ + .unk2 = 3827, + RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901), + }, + { .channel = 149, + .freq = 5745, /* MHz */ + .unk2 = 3830, + RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901), + }, + { .channel = 150, + .freq = 5750, /* MHz */ + .unk2 = 3833, + RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901), + }, + { .channel = 151, + .freq = 5755, /* MHz */ + .unk2 = 3837, + RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801), + }, + { .channel = 152, + .freq = 5760, /* MHz */ + .unk2 = 3840, + RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 153, + .freq = 5765, /* MHz */ + .unk2 = 3843, + RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 154, + .freq = 5770, /* MHz */ + .unk2 = 3847, + RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701), + }, + { .channel = 155, + .freq = 5775, /* MHz */ + .unk2 = 3850, + RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701), + }, + { .channel = 156, + .freq = 5780, /* MHz */ + .unk2 = 3853, + RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601), + }, + { .channel = 157, + .freq = 5785, /* MHz */ + .unk2 = 3857, + RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601), + }, + { .channel = 158, + .freq = 5790, /* MHz */ + .unk2 = 3860, + RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601), + }, + { .channel = 159, + .freq = 5795, /* MHz */ + .unk2 = 3863, + RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501), + }, + { .channel = 160, + .freq = 5800, /* MHz */ + .unk2 = 3867, + RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501), + }, + { .channel = 161, + .freq = 5805, /* MHz */ + .unk2 = 3870, + RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401), + }, + { .channel = 162, + .freq = 5810, /* MHz */ + .unk2 = 3873, + RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401), + }, + { .channel = 163, + .freq = 5815, /* MHz */ + .unk2 = 3877, + RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401), + }, + { .channel = 164, + .freq = 5820, /* MHz */ + .unk2 = 3880, + RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301), + }, + { .channel = 165, + .freq = 5825, /* MHz */ + .unk2 = 3883, + RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301), + }, + { .channel = 166, + .freq = 5830, /* MHz */ + .unk2 = 3887, + RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201), + }, + { .channel = 168, + .freq = 5840, /* MHz */ + .unk2 = 3893, + RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201), + }, + { .channel = 170, + .freq = 5850, /* MHz */ + .unk2 = 3900, + RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101), + }, + { .channel = 172, + .freq = 5860, /* MHz */ + .unk2 = 3907, + RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001), + }, + { .channel = 174, + .freq = 5870, /* MHz */ + .unk2 = 3913, + RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01), + }, + { .channel = 176, + .freq = 5880, /* MHz */ + .unk2 = 3920, + RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01), + }, + { .channel = 178, + .freq = 5890, /* MHz */ + .unk2 = 3927, + RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01), + }, + { .channel = 180, + .freq = 5900, /* MHz */ + .unk2 = 3933, + RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01), + }, + { .channel = 182, + .freq = 5910, /* MHz */ + .unk2 = 3940, + RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01), + }, + { .channel = 1, + .freq = 2412, /* MHz */ + .unk2 = 3216, + RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, + 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80), + PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304), + }, + { .channel = 2, + .freq = 2417, /* MHz */ + .unk2 = 3223, + RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, + 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80), + PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104), + }, + { .channel = 3, + .freq = 2422, /* MHz */ + .unk2 = 3229, + RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04), + }, + { .channel = 4, + .freq = 2427, /* MHz */ + .unk2 = 3236, + RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04), + }, + { .channel = 5, + .freq = 2432, /* MHz */ + .unk2 = 3243, + RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, + 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80), + PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04), + }, + { .channel = 6, + .freq = 2437, /* MHz */ + .unk2 = 3249, + RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, + 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80), + PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804), + }, + { .channel = 7, + .freq = 2442, /* MHz */ + .unk2 = 3256, + RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, + 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80), + PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604), + }, + { .channel = 8, + .freq = 2447, /* MHz */ + .unk2 = 3263, + RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, + 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80), + PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404), + }, + { .channel = 9, + .freq = 2452, /* MHz */ + .unk2 = 3269, + RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, + 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80), + PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104), + }, + { .channel = 10, + .freq = 2457, /* MHz */ + .unk2 = 3276, + RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, + 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80), + PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04), + }, + { .channel = 11, + .freq = 2462, /* MHz */ + .unk2 = 3283, + RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, + 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80), + PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04), + }, + { .channel = 12, + .freq = 2467, /* MHz */ + .unk2 = 3289, + RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, + 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80), + PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04), + }, + { .channel = 13, + .freq = 2472, /* MHz */ + .unk2 = 3296, + RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, + 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80), + PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904), + }, + { .channel = 14, + .freq = 2484, /* MHz */ + .unk2 = 3312, + RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, + 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80), + PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404), + }, +}; + +const struct b43_nphy_channeltab_entry * +b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel) +{ + const struct b43_nphy_channeltab_entry *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) { + e = &(b43_nphy_channeltab[i]); + if (e->channel == channel) + return e; + } + + return NULL; +} + + +const u8 b43_ntab_adjustpower0[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, +}; + +const u8 b43_ntab_adjustpower1[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, +}; + +const u16 b43_ntab_bdi[] = { + 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, +}; + +const u32 b43_ntab_channelest[] = { + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, +}; + +const u8 b43_ntab_estimatepowerlt0[] = { + 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, + 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, +}; + +const u8 b43_ntab_estimatepowerlt1[] = { + 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, + 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, +}; + +const u8 b43_ntab_framelookup[] = { + 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, + 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, + 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, + 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, +}; + +const u32 b43_ntab_framestruct[] = { + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x09804506, 0x00100030, 0x09804507, 0x00100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028, + 0x0980450E, 0x00100038, 0x0980450F, 0x00100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A04, 0x00100000, 0x11008A05, 0x00100020, + 0x1980C506, 0x00100030, 0x21810506, 0x00100030, + 0x21810506, 0x00100030, 0x01800504, 0x00100030, + 0x11808505, 0x00100030, 0x29814507, 0x01100030, + 0x00000A04, 0x00100000, 0x11008A05, 0x00100020, + 0x21810506, 0x00100030, 0x21810506, 0x00100030, + 0x29814507, 0x01100030, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x2181050E, 0x00100038, + 0x2181050E, 0x00100038, 0x0180050C, 0x00100038, + 0x1180850D, 0x00100038, 0x2981450F, 0x01100038, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x2181050E, 0x00100038, 0x2181050E, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x1980C506, 0x00100030, 0x1980C506, 0x00100030, + 0x11808504, 0x00100030, 0x3981CA05, 0x00100030, + 0x29814507, 0x01100030, 0x00000000, 0x00000000, + 0x10008A04, 0x00100000, 0x3981CA05, 0x00100030, + 0x1980C506, 0x00100030, 0x29814507, 0x01100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x1980C50E, 0x00100038, + 0x1180850C, 0x00100038, 0x3981CA0D, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x10008A0C, 0x00100008, 0x3981CA0D, 0x00100038, + 0x1980C50E, 0x00100038, 0x2981450F, 0x01100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x02001405, 0x00100040, + 0x0B004A06, 0x01900060, 0x13008A06, 0x01900060, + 0x13008A06, 0x01900060, 0x43020A04, 0x00100060, + 0x1B00CA05, 0x00100060, 0x23010A07, 0x01500060, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x13008A06, 0x01900060, 0x13008A06, 0x01900060, + 0x23010A07, 0x01500060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x0200140D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x23010A0F, 0x01500070, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x50029404, 0x00100000, 0x32019405, 0x00100040, + 0x0B004A06, 0x01900060, 0x0B004A06, 0x01900060, + 0x5B02CA04, 0x00100060, 0x3B01D405, 0x00100060, + 0x23010A07, 0x01500060, 0x00000000, 0x00000000, + 0x5802D404, 0x00100000, 0x3B01D405, 0x00100060, + 0x0B004A06, 0x01900060, 0x23010A07, 0x01500060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x5002940C, 0x00100010, 0x3201940D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x0B004A0E, 0x01900070, + 0x5B02CA0C, 0x00100070, 0x3B01D40D, 0x00100070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x5802D40C, 0x00100010, 0x3B01D40D, 0x00100070, + 0x0B004A0E, 0x01900070, 0x23010A0F, 0x01500070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x000F4800, 0x62031405, 0x00100040, + 0x53028A06, 0x01900060, 0x53028A07, 0x01900060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x000F4810, 0x6203140D, 0x00100050, + 0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x2181050E, 0x00100038, + 0x2181050E, 0x00100038, 0x0180050C, 0x00100038, + 0x1180850D, 0x00100038, 0x1181850D, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x2181050E, 0x00100038, 0x2181050E, 0x00100038, + 0x1181850D, 0x00100038, 0x2981450F, 0x01100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x0180C506, 0x00100030, 0x0180C506, 0x00100030, + 0x2180C50C, 0x00100030, 0x49820A0D, 0x0016A130, + 0x41824A0D, 0x0016A130, 0x2981450F, 0x01100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2000CA0C, 0x00100000, 0x49820A0D, 0x0016A130, + 0x1980C50E, 0x00100030, 0x41824A0D, 0x0016A130, + 0x2981450F, 0x01100030, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x0200140D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x1B014A0D, 0x00100070, 0x23010A0F, 0x01500070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x50029404, 0x00100000, 0x32019405, 0x00100040, + 0x03004A06, 0x01900060, 0x03004A06, 0x01900060, + 0x6B030A0C, 0x00100060, 0x4B02140D, 0x0016A160, + 0x4302540D, 0x0016A160, 0x23010A0F, 0x01500060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6B03140C, 0x00100060, 0x4B02140D, 0x0016A160, + 0x0B004A0E, 0x01900060, 0x4302540D, 0x0016A160, + 0x23010A0F, 0x01500060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x53028A06, 0x01900060, 0x5B02CA06, 0x01900060, + 0x5B02CA06, 0x01900060, 0x43020A04, 0x00100060, + 0x1B00CA05, 0x00100060, 0x53028A07, 0x0190C060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x53028A0E, 0x01900070, 0x5B02CA0E, 0x01900070, + 0x5B02CA0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x53028A0F, 0x0190C070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x5B02CA06, 0x01900060, 0x5B02CA06, 0x01900060, + 0x53028A07, 0x0190C060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x5B02CA0E, 0x01900070, 0x5B02CA0E, 0x01900070, + 0x53028A0F, 0x0190C070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_gainctl0[] = { + 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, + 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, + 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, + 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38, + 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336, + 0x006B0435, 0x006A0535, 0x00690634, 0x00680734, + 0x00670833, 0x00660933, 0x00650A32, 0x00640B32, + 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30, + 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E, + 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C, + 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A, + 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28, + 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326, + 0x004B0425, 0x004A0525, 0x00490624, 0x00480724, + 0x00470823, 0x00460923, 0x00450A22, 0x00440B22, + 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20, + 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E, + 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C, + 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A, + 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18, + 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316, + 0x002B0415, 0x002A0515, 0x00290614, 0x00280714, + 0x00270813, 0x00260913, 0x00250A12, 0x00240B12, + 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10, + 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E, + 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C, + 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A, + 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08, + 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306, + 0x000B0405, 0x000A0505, 0x00090604, 0x00080704, + 0x00070803, 0x00060903, 0x00050A02, 0x00040B02, + 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, +}; + +const u32 b43_ntab_gainctl1[] = { + 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, + 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, + 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, + 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38, + 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336, + 0x006B0435, 0x006A0535, 0x00690634, 0x00680734, + 0x00670833, 0x00660933, 0x00650A32, 0x00640B32, + 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30, + 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E, + 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C, + 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A, + 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28, + 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326, + 0x004B0425, 0x004A0525, 0x00490624, 0x00480724, + 0x00470823, 0x00460923, 0x00450A22, 0x00440B22, + 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20, + 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E, + 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C, + 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A, + 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18, + 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316, + 0x002B0415, 0x002A0515, 0x00290614, 0x00280714, + 0x00270813, 0x00260913, 0x00250A12, 0x00240B12, + 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10, + 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E, + 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C, + 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A, + 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08, + 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306, + 0x000B0405, 0x000A0505, 0x00090604, 0x00080704, + 0x00070803, 0x00060903, 0x00050A02, 0x00040B02, + 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, +}; + +const u32 b43_ntab_intlevel[] = { + 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, + 0x00C1188D, 0x080024D2, 0x00000070, +}; + +const u32 b43_ntab_iqlt0[] = { + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, +}; + +const u32 b43_ntab_iqlt1[] = { + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, +}; + +const u16 b43_ntab_loftlt0[] = { + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, +}; + +const u16 b43_ntab_loftlt1[] = { + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, +}; + +const u8 b43_ntab_mcs[] = { + 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, + 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, + 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, + 0xC0, 0xC8, 0xCA, 0xD0, 0xD2, 0xD9, 0xDA, 0xDC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x04, 0x08, 0x09, 0x0A, 0x0C, + 0x10, 0x11, 0x12, 0x14, 0x18, 0x19, 0x1A, 0x1C, + 0x20, 0x21, 0x22, 0x24, 0x40, 0x41, 0x42, 0x44, + 0x48, 0x49, 0x4A, 0x4C, 0x50, 0x51, 0x52, 0x54, + 0x58, 0x59, 0x5A, 0x5C, 0x60, 0x61, 0x62, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const u32 b43_ntab_noisevar10[] = { + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, +}; + +const u32 b43_ntab_noisevar11[] = { + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, +}; + +const u16 b43_ntab_pilot[] = { + 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, + 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, + 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, + 0xFFA0, 0xFF28, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFF82, 0xFFA0, 0xFF28, 0xFF0A, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xF83F, 0xFA1F, 0xFA97, 0xFAB5, + 0xF2BD, 0xF0BF, 0xFFFF, 0xFFFF, 0xF017, 0xF815, + 0xF215, 0xF095, 0xF035, 0xF01D, 0xFFFF, 0xFFFF, + 0xFF08, 0xFF02, 0xFF80, 0xFF20, 0xFF08, 0xFF02, + 0xFF80, 0xFF20, 0xF01F, 0xF817, 0xFA15, 0xF295, + 0xF0B5, 0xF03D, 0xFFFF, 0xFFFF, 0xF82A, 0xFA0A, + 0xFA82, 0xFAA0, 0xF2A8, 0xF0AA, 0xFFFF, 0xFFFF, + 0xF002, 0xF800, 0xF200, 0xF080, 0xF020, 0xF008, + 0xFFFF, 0xFFFF, 0xF00A, 0xF802, 0xFA00, 0xF280, + 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, +}; + +const u32 b43_ntab_pilotlt[] = { + 0x76540123, 0x62407351, 0x76543201, 0x76540213, + 0x76540123, 0x76430521, +}; + +const u32 b43_ntab_tdi20a0[] = { + 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, + 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, + 0x00020301, 0x00030504, 0x00040708, 0x0005090B, + 0x00064B8E, 0x00095291, 0x000A5494, 0x000B9718, + 0x000C9927, 0x000D9B2A, 0x000EDD2E, 0x000FDF31, + 0x000101B4, 0x000243B7, 0x000345BB, 0x000447BE, + 0x00058982, 0x00068C05, 0x00099309, 0x000A950C, + 0x000BD78F, 0x000CD992, 0x000DDB96, 0x000F1D99, + 0x00005FA8, 0x0001422C, 0x0002842F, 0x00038632, + 0x00048835, 0x0005CA38, 0x0006CCBC, 0x0009D3BF, + 0x000B1603, 0x000C1806, 0x000D1A0A, 0x000E1C0D, + 0x000F5E10, 0x00008093, 0x00018297, 0x0002C49A, + 0x0003C680, 0x0004C880, 0x00060B00, 0x00070D00, + 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi20a1[] = { + 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, + 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, + 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, + 0x0000488E, 0x00018B91, 0x0002D214, 0x0003D418, + 0x0004D6A7, 0x000618AA, 0x00071AAE, 0x0009DCB1, + 0x000B1EB4, 0x000C0137, 0x000D033B, 0x000E053E, + 0x000F4702, 0x00008905, 0x00020C09, 0x0003128C, + 0x0004148F, 0x00051712, 0x00065916, 0x00091B19, + 0x000A1D28, 0x000B5F2C, 0x000C41AF, 0x000D43B2, + 0x000E85B5, 0x000F87B8, 0x0000C9BC, 0x00024CBF, + 0x00035303, 0x00045506, 0x0005978A, 0x0006998D, + 0x00095B90, 0x000A5D93, 0x000B9F97, 0x000C821A, + 0x000D8400, 0x000EC600, 0x000FC800, 0x00010A00, + 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi40a0[] = { + 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, + 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, + 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, + 0x00056447, 0x00072DD0, 0x0008B6DA, 0x000A02E3, + 0x000B8C6C, 0x000D15F6, 0x0011E484, 0x0013AE0D, + 0x00153717, 0x00168320, 0x00180CA9, 0x00199633, + 0x001B6548, 0x001CEED1, 0x001EB7DB, 0x0000C3E4, + 0x00024D6D, 0x000416F7, 0x0005A585, 0x00076F0F, + 0x0008F818, 0x000A4421, 0x000BCDAB, 0x000D9734, + 0x00122649, 0x0013EFD2, 0x001578DC, 0x0016C4E5, + 0x00184E6E, 0x001A17F8, 0x001BA686, 0x001D3010, + 0x001EF999, 0x00010522, 0x00028EAC, 0x00045835, + 0x0005E74A, 0x0007B0D3, 0x00093A5D, 0x000A85E6, + 0x000C0F6F, 0x000DD8F9, 0x00126787, 0x00143111, + 0x0015BA9A, 0x00170623, 0x00188FAD, 0x001A5936, + 0x001BE84B, 0x001DB1D4, 0x001F3B5E, 0x000146E7, + 0x00031070, 0x000499FA, 0x00062888, 0x0007F212, + 0x00097B9B, 0x000AC7A4, 0x000C50AE, 0x000E1A37, + 0x0012A94C, 0x001472D5, 0x0015FC5F, 0x00174868, + 0x0018D171, 0x001A9AFB, 0x001C2989, 0x001DF313, + 0x001F7C9C, 0x000188A5, 0x000351AF, 0x0004DB38, + 0x0006AA4D, 0x000833D7, 0x0009BD60, 0x000B0969, + 0x000C9273, 0x000E5BFC, 0x00132A8A, 0x0014B414, + 0x00163D9D, 0x001789A6, 0x001912B0, 0x001ADC39, + 0x001C6BCE, 0x001E34D8, 0x001FBE61, 0x0001CA6A, + 0x00039374, 0x00051CFD, 0x0006EC0B, 0x00087515, + 0x0009FE9E, 0x000B4AA7, 0x000CD3B1, 0x000E9D3A, + 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi40a1[] = { + 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, + 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, + 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, + 0x00155C37, 0x0016EACB, 0x00187454, 0x001A3DDE, + 0x001B89E7, 0x001D12F0, 0x001F1CFA, 0x00016B88, + 0x00033492, 0x0004BE1B, 0x00060A24, 0x0007D32E, + 0x00095D38, 0x000AEC4C, 0x000C7555, 0x000E3EDF, + 0x00124AE8, 0x001413F1, 0x0015A37B, 0x00172C89, + 0x0018B593, 0x001A419C, 0x001BCB25, 0x001D942F, + 0x001F63B9, 0x0001AD4D, 0x00037657, 0x0004C260, + 0x00068BE9, 0x000814F3, 0x0009A47C, 0x000B2D8A, + 0x000CB694, 0x000E429D, 0x00128C26, 0x001455B0, + 0x0015E4BA, 0x00176E4E, 0x0018F758, 0x001A8361, + 0x001C0CEA, 0x001DD674, 0x001FA57D, 0x0001EE8B, + 0x0003B795, 0x0005039E, 0x0006CD27, 0x000856B1, + 0x0009E5C6, 0x000B6F4F, 0x000CF859, 0x000E8462, + 0x00130DEB, 0x00149775, 0x00162603, 0x0017AF8C, + 0x00193896, 0x001AC49F, 0x001C4E28, 0x001E17B2, + 0x0000A6C7, 0x00023050, 0x0003F9DA, 0x00054563, + 0x00070EEC, 0x00089876, 0x000A2704, 0x000BB08D, + 0x000D3A17, 0x001185A0, 0x00134F29, 0x0014D8B3, + 0x001667C8, 0x0017F151, 0x00197ADB, 0x001B0664, + 0x001C8FED, 0x001E5977, 0x0000E805, 0x0002718F, + 0x00043B18, 0x000586A1, 0x0007502B, 0x0008D9B4, + 0x000A68C9, 0x000BF252, 0x000DBBDC, 0x0011C7E5, + 0x001390EE, 0x00151A78, 0x0016A906, 0x00183290, + 0x0019BC19, 0x001B4822, 0x001CD12C, 0x001E9AB5, + 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdtrn[] = { + 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, + 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, + 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, + 0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050, + 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, + 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, + 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, + 0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050, + 0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246, + 0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C, + 0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61, + 0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D, + 0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246, + 0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C, + 0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61, + 0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D, + 0xFA58FA58, 0xF895043B, 0xFF4C09C0, 0xFBC6FFA8, + 0xFB84F384, 0x0798F6F9, 0x05760122, 0x058409F6, + 0x0B500000, 0x05B7F542, 0x08860432, 0x06DDFEE7, + 0xFB84F384, 0xF9D90664, 0xF7E8025C, 0x00FFF7BD, + 0x05A805A8, 0xF7BD00FF, 0x025CF7E8, 0x0664F9D9, + 0xF384FB84, 0xFEE706DD, 0x04320886, 0xF54205B7, + 0x00000B50, 0x09F60584, 0x01220576, 0xF6F90798, + 0xF384FB84, 0xFFA8FBC6, 0x09C0FF4C, 0x043BF895, + 0x02D402D4, 0x07DE0270, 0xFC96079C, 0xF90AFE94, + 0xFE00FF2C, 0x02D4065D, 0x092A0096, 0x0014FBB8, + 0xFD2CFD2C, 0x076AFB3C, 0x0096F752, 0xF991FD87, + 0xFB2C0200, 0xFEB8F960, 0x08E0FC96, 0x049802A8, + 0xFD2CFD2C, 0x02A80498, 0xFC9608E0, 0xF960FEB8, + 0x0200FB2C, 0xFD87F991, 0xF7520096, 0xFB3C076A, + 0xFD2CFD2C, 0xFBB80014, 0x0096092A, 0x065D02D4, + 0xFF2CFE00, 0xFE94F90A, 0x079CFC96, 0x027007DE, + 0x02D402D4, 0x027007DE, 0x079CFC96, 0xFE94F90A, + 0xFF2CFE00, 0x065D02D4, 0x0096092A, 0xFBB80014, + 0xFD2CFD2C, 0xFB3C076A, 0xF7520096, 0xFD87F991, + 0x0200FB2C, 0xF960FEB8, 0xFC9608E0, 0x02A80498, + 0xFD2CFD2C, 0x049802A8, 0x08E0FC96, 0xFEB8F960, + 0xFB2C0200, 0xF991FD87, 0x0096F752, 0x076AFB3C, + 0xFD2CFD2C, 0x0014FBB8, 0x092A0096, 0x02D4065D, + 0xFE00FF2C, 0xF90AFE94, 0xFC96079C, 0x07DE0270, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D, + 0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF, + 0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8, + 0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7, + 0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3, + 0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841, + 0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608, + 0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759, + 0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D, + 0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF, + 0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8, + 0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7, + 0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3, + 0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841, + 0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608, + 0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759, + 0x061C061C, 0xFF30009D, 0xFFB21141, 0xFD87FB54, + 0xF65DFE59, 0x02EEF99E, 0x0166F03C, 0xFFF809B6, + 0x000008A4, 0x000AF42B, 0x00EFF577, 0xFA840BF2, + 0xFC02FF51, 0x08260F67, 0xFFF0036F, 0x0842F9C3, + 0x00000000, 0x063DF7BE, 0xFC910010, 0xF099F7DA, + 0x00AF03FE, 0xF40E057C, 0x0A89FF11, 0x0BD5FFF6, + 0xF75C0000, 0xF64A0008, 0x0FC4FE9A, 0x0662FD12, + 0x01A709A3, 0x04AC0279, 0xEEBF004E, 0xFF6300D0, + 0xF9E4F9E4, 0x00D0FF63, 0x004EEEBF, 0x027904AC, + 0x09A301A7, 0xFD120662, 0xFE9A0FC4, 0x0008F64A, + 0x0000F75C, 0xFFF60BD5, 0xFF110A89, 0x057CF40E, + 0x03FE00AF, 0xF7DAF099, 0x0010FC91, 0xF7BE063D, + 0x00000000, 0xF9C30842, 0x036FFFF0, 0x0F670826, + 0xFF51FC02, 0x0BF2FA84, 0xF57700EF, 0xF42B000A, + 0x08A40000, 0x09B6FFF8, 0xF03C0166, 0xF99E02EE, + 0xFE59F65D, 0xFB54FD87, 0x1141FFB2, 0x009DFF30, + 0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59, + 0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766, + 0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986, + 0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB, + 0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7, + 0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A, + 0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A, + 0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705, + 0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59, + 0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766, + 0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986, + 0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB, + 0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7, + 0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A, + 0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A, + 0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705, + 0xFA58FA58, 0xF8F0FE00, 0x0448073D, 0xFDC9FE46, + 0xF9910258, 0x089D0407, 0xFD5CF71A, 0x02AFFDE0, + 0x083E0496, 0xFF5A0740, 0xFF7AFD97, 0x00FE01F1, + 0x0009082E, 0xFA94FF75, 0xFECDF8EA, 0xFFB0F693, + 0xFD2CFA58, 0x0433FF16, 0xFBA405DD, 0xFA610341, + 0x06A606CB, 0x0039FD2D, 0x0677FA97, 0x01FA05E0, + 0xF896003E, 0x075A068B, 0x012CFC3E, 0xFA23F98D, + 0xFC7CFD43, 0xFF90FC0D, 0x01C10982, 0x00C601D6, + 0xFD2CFD2C, 0x01D600C6, 0x098201C1, 0xFC0DFF90, + 0xFD43FC7C, 0xF98DFA23, 0xFC3E012C, 0x068B075A, + 0x003EF896, 0x05E001FA, 0xFA970677, 0xFD2D0039, + 0x06CB06A6, 0x0341FA61, 0x05DDFBA4, 0xFF160433, + 0xFA58FD2C, 0xF693FFB0, 0xF8EAFECD, 0xFF75FA94, + 0x082E0009, 0x01F100FE, 0xFD97FF7A, 0x0740FF5A, + 0x0496083E, 0xFDE002AF, 0xF71AFD5C, 0x0407089D, + 0x0258F991, 0xFE46FDC9, 0x073D0448, 0xFE00F8F0, + 0xFD2CFD2C, 0xFCE00500, 0xFC09FDDC, 0xFE680157, + 0x04C70571, 0xFC3AFF21, 0xFCD70228, 0x056D0277, + 0x0200FE00, 0x0022F927, 0xFE3C032B, 0xFC44FF3C, + 0x03E9FBDB, 0x04570313, 0x04C9FF5C, 0x000D03B8, + 0xFA580000, 0xFBE900D2, 0xF9D0FE0B, 0x0125FDF9, + 0x042501BF, 0x0328FA2B, 0xFFA902F0, 0xFA250157, + 0x0200FE00, 0x03740438, 0xFF0405FD, 0x030CFE52, + 0x0037FB39, 0xFF6904C5, 0x04F8FD23, 0xFD31FC1B, + 0xFD2CFD2C, 0xFC1BFD31, 0xFD2304F8, 0x04C5FF69, + 0xFB390037, 0xFE52030C, 0x05FDFF04, 0x04380374, + 0xFE000200, 0x0157FA25, 0x02F0FFA9, 0xFA2B0328, + 0x01BF0425, 0xFDF90125, 0xFE0BF9D0, 0x00D2FBE9, + 0x0000FA58, 0x03B8000D, 0xFF5C04C9, 0x03130457, + 0xFBDB03E9, 0xFF3CFC44, 0x032BFE3C, 0xF9270022, + 0xFE000200, 0x0277056D, 0x0228FCD7, 0xFF21FC3A, + 0x057104C7, 0x0157FE68, 0xFDDCFC09, 0x0500FCE0, + 0xFD2CFD2C, 0x0500FCE0, 0xFDDCFC09, 0x0157FE68, + 0x057104C7, 0xFF21FC3A, 0x0228FCD7, 0x0277056D, + 0xFE000200, 0xF9270022, 0x032BFE3C, 0xFF3CFC44, + 0xFBDB03E9, 0x03130457, 0xFF5C04C9, 0x03B8000D, + 0x0000FA58, 0x00D2FBE9, 0xFE0BF9D0, 0xFDF90125, + 0x01BF0425, 0xFA2B0328, 0x02F0FFA9, 0x0157FA25, + 0xFE000200, 0x04380374, 0x05FDFF04, 0xFE52030C, + 0xFB390037, 0x04C5FF69, 0xFD2304F8, 0xFC1BFD31, + 0xFD2CFD2C, 0xFD31FC1B, 0x04F8FD23, 0xFF6904C5, + 0x0037FB39, 0x030CFE52, 0xFF0405FD, 0x03740438, + 0x0200FE00, 0xFA250157, 0xFFA902F0, 0x0328FA2B, + 0x042501BF, 0x0125FDF9, 0xF9D0FE0B, 0xFBE900D2, + 0xFA580000, 0x000D03B8, 0x04C9FF5C, 0x04570313, + 0x03E9FBDB, 0xFC44FF3C, 0xFE3C032B, 0x0022F927, + 0x0200FE00, 0x056D0277, 0xFCD70228, 0xFC3AFF21, + 0x04C70571, 0xFE680157, 0xFC09FDDC, 0xFCE00500, + 0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E, + 0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C, + 0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926, + 0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942, + 0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382, + 0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4, + 0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA, + 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, + 0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E, + 0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C, + 0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926, + 0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942, + 0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382, + 0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4, + 0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA, + 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, +}; + +const u32 b43_ntab_tmap[] = { + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, + 0x11000000, 0x1111F111, 0x11111111, 0x111111F1, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x000AA888, + 0x88880000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA2222220, 0x22222222, 0x22C22222, 0x00000222, + 0x22000000, 0x2222A222, 0x22222222, 0x222222A2, + 0xF1111110, 0x11111111, 0x11F11111, 0x00011111, + 0x11110000, 0x1111F111, 0x11111111, 0x111111F1, + 0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00088AAA, + 0xAAAA0000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xAAA8AAA0, 0x8AAA8AAA, 0xAA8A8A8A, 0x000AAA88, + 0x8AAA0000, 0xAAA8A888, 0x8AA88A8A, 0x8A88A888, + 0x08080A00, 0x0A08080A, 0x080A0A08, 0x00080808, + 0x080A0000, 0x080A0808, 0x080A0808, 0x0A0A0A08, + 0xA0A0A0A0, 0x80A0A080, 0x8080A0A0, 0x00008080, + 0x80A00000, 0x80A080A0, 0xA080A0A0, 0x8080A0A0, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x99999000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888, + 0x22000000, 0x2222B222, 0x22222222, 0x222222B2, + 0xB2222220, 0x22222222, 0x22D22222, 0x00000222, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x33000000, 0x3333B333, 0x33333333, 0x333333B3, + 0xB3333330, 0x33333333, 0x33D33333, 0x00000333, + 0x22000000, 0x2222A222, 0x22222222, 0x222222A2, + 0xA2222220, 0x22222222, 0x22C22222, 0x00000222, + 0x99B99B00, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB99, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888, + 0x22222200, 0x2222F222, 0x22222222, 0x222222F2, + 0x22222222, 0x22222222, 0x22F22222, 0x00000222, + 0x11000000, 0x1111F111, 0x11111111, 0x11111111, + 0xF1111111, 0x11111111, 0x11F11111, 0x01111111, + 0xBB9BB900, 0xB9B9BB99, 0xB99BBBBB, 0xBBBB9B9B, + 0xB9BB99BB, 0xB99999B9, 0xB9B9B99B, 0x00000BBB, + 0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xA8AA88AA, 0xA88888A8, 0xA8A8A88A, 0x0A888AAA, + 0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00000AAA, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0xBBBBBB00, 0x999BBBBB, 0x9BB99B9B, 0xB9B9B9BB, + 0xB9B99BBB, 0xB9B9B9BB, 0xB9BB9B99, 0x00000999, + 0x8A000000, 0xAA88A888, 0xA88888AA, 0xA88A8A88, + 0xA88AA88A, 0x88A8AAAA, 0xA8AA8AAA, 0x0888A88A, + 0x0B0B0B00, 0x090B0B0B, 0x0B090B0B, 0x0909090B, + 0x09090B0B, 0x09090B0B, 0x09090B09, 0x00000909, + 0x0A000000, 0x0A080808, 0x080A080A, 0x080A0A08, + 0x080A080A, 0x0808080A, 0x0A0A0A08, 0x0808080A, + 0xB0B0B000, 0x9090B0B0, 0x90B09090, 0xB0B0B090, + 0xB0B090B0, 0x90B0B0B0, 0xB0B09090, 0x00000090, + 0x80000000, 0xA080A080, 0xA08080A0, 0xA0808080, + 0xA080A080, 0x80A0A0A0, 0xA0A080A0, 0x00A0A0A0, + 0x22000000, 0x2222F222, 0x22222222, 0x222222F2, + 0xF2222220, 0x22222222, 0x22F22222, 0x00000222, + 0x11000000, 0x1111F111, 0x11111111, 0x111111F1, + 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, + 0x33000000, 0x3333F333, 0x33333333, 0x333333F3, + 0xF3333330, 0x33333333, 0x33F33333, 0x00000333, + 0x22000000, 0x2222F222, 0x22222222, 0x222222F2, + 0xF2222220, 0x22222222, 0x22F22222, 0x00000222, + 0x99000000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88888000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888, + 0x88A88A00, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static inline void assert_ntab_array_sizes(void) +{ +#undef check +#define check(table, size) \ + BUILD_BUG_ON(ARRAY_SIZE(b43_ntab_##table) != B43_NTAB_##size##_SIZE) + + check(adjustpower0, C0_ADJPLT); + check(adjustpower1, C1_ADJPLT); + check(bdi, BDI); + check(channelest, CHANEST); + check(estimatepowerlt0, C0_ESTPLT); + check(estimatepowerlt1, C1_ESTPLT); + check(framelookup, FRAMELT); + check(framestruct, FRAMESTRUCT); + check(gainctl0, C0_GAINCTL); + check(gainctl1, C1_GAINCTL); + check(intlevel, INTLEVEL); + check(iqlt0, C0_IQLT); + check(iqlt1, C1_IQLT); + check(loftlt0, C0_LOFEEDTH); + check(loftlt1, C1_LOFEEDTH); + check(mcs, MCS); + check(noisevar10, NOISEVAR10); + check(noisevar11, NOISEVAR11); + check(pilot, PILOT); + check(pilotlt, PILOTLT); + check(tdi20a0, TDI20A0); + check(tdi20a1, TDI20A1); + check(tdi40a0, TDI40A0); + check(tdi40a1, TDI40A1); + check(tdtrn, TDTRN); + check(tmap, TMAP); + +#undef check +} + +void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) +{ + u32 type; + + type = offset & B43_NTAB_TYPEMASK; + offset &= 0xFFFF; + + switch (type) { + case B43_NTAB_8BIT: + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_16BIT: + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_32BIT: + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + + return; + + /* Some compiletime assertions... */ + assert_ntab_array_sizes(); +} diff --git a/package/b43/src/tables_nphy.h b/package/b43/src/tables_nphy.h new file mode 100644 index 0000000000..4d498b053e --- /dev/null +++ b/package/b43/src/tables_nphy.h @@ -0,0 +1,159 @@ +#ifndef B43_TABLES_NPHY_H_ +#define B43_TABLES_NPHY_H_ + +#include <linux/types.h> + + +struct b43_nphy_channeltab_entry { + /* The channel number */ + u8 channel; + /* Radio register values on channelswitch */ + u8 radio_pll_ref; + u8 radio_rf_pllmod0; + u8 radio_rf_pllmod1; + u8 radio_vco_captail; + u8 radio_vco_cal1; + u8 radio_vco_cal2; + u8 radio_pll_lfc1; + u8 radio_pll_lfr1; + u8 radio_pll_lfc2; + u8 radio_lgbuf_cenbuf; + u8 radio_lgen_tune1; + u8 radio_lgen_tune2; + u8 radio_c1_lgbuf_atune; + u8 radio_c1_lgbuf_gtune; + u8 radio_c1_rx_rfr1; + u8 radio_c1_tx_pgapadtn; + u8 radio_c1_tx_mxbgtrim; + u8 radio_c2_lgbuf_atune; + u8 radio_c2_lgbuf_gtune; + u8 radio_c2_rx_rfr1; + u8 radio_c2_tx_pgapadtn; + u8 radio_c2_tx_mxbgtrim; + /* PHY register values on channelswitch */ + u16 phy_bw1a; + u16 phy_bw2; + u16 phy_bw3; + u16 phy_bw4; + u16 phy_bw5; + u16 phy_bw6; + /* The channel frequency in MHz */ + u16 freq; + /* An unknown value */ + u16 unk2; +}; + + +struct b43_wldev; + +/* Upload the default register value table. + * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz + * table is uploaded. If "ignore_uploadflag" is true, we upload any value + * and ignore the "UPLOAD" flag. */ +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag); + + +/* Get the NPHY Channel Switch Table entry for a channel number. + * Returns NULL on failure to find an entry. */ +const struct b43_nphy_channeltab_entry * +b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); + + +/* The N-PHY tables. */ + +#define B43_NTAB_TYPEMASK 0xF0000000 +#define B43_NTAB_8BIT 0x10000000 +#define B43_NTAB_16BIT 0x20000000 +#define B43_NTAB_32BIT 0x30000000 +#define B43_NTAB8(table, offset) (((table) << 10) | (offset) | B43_NTAB_8BIT) +#define B43_NTAB16(table, offset) (((table) << 10) | (offset) | B43_NTAB_16BIT) +#define B43_NTAB32(table, offset) (((table) << 10) | (offset) | B43_NTAB_32BIT) + +/* Static N-PHY tables */ +#define B43_NTAB_FRAMESTRUCT B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */ +#define B43_NTAB_FRAMESTRUCT_SIZE 832 +#define B43_NTAB_FRAMELT B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */ +#define B43_NTAB_FRAMELT_SIZE 32 +#define B43_NTAB_TMAP B43_NTAB32(0x0C, 0x000) /* T Map Table */ +#define B43_NTAB_TMAP_SIZE 448 +#define B43_NTAB_TDTRN B43_NTAB32(0x0E, 0x000) /* TDTRN Table */ +#define B43_NTAB_TDTRN_SIZE 704 +#define B43_NTAB_INTLEVEL B43_NTAB32(0x0D, 0x000) /* Int Level Table */ +#define B43_NTAB_INTLEVEL_SIZE 7 +#define B43_NTAB_PILOT B43_NTAB16(0x0B, 0x000) /* Pilot Table */ +#define B43_NTAB_PILOT_SIZE 88 +#define B43_NTAB_PILOTLT B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */ +#define B43_NTAB_PILOTLT_SIZE 6 +#define B43_NTAB_TDI20A0 B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */ +#define B43_NTAB_TDI20A0_SIZE 55 +#define B43_NTAB_TDI20A1 B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */ +#define B43_NTAB_TDI20A1_SIZE 55 +#define B43_NTAB_TDI40A0 B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */ +#define B43_NTAB_TDI40A0_SIZE 110 +#define B43_NTAB_TDI40A1 B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */ +#define B43_NTAB_TDI40A1_SIZE 110 +#define B43_NTAB_BDI B43_NTAB16(0x15, 0x000) /* BDI Table */ +#define B43_NTAB_BDI_SIZE 6 +#define B43_NTAB_CHANEST B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */ +#define B43_NTAB_CHANEST_SIZE 96 +#define B43_NTAB_MCS B43_NTAB8 (0x12, 0x000) /* MCS Table */ +#define B43_NTAB_MCS_SIZE 128 + +/* Volatile N-PHY tables */ +#define B43_NTAB_NOISEVAR10 B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */ +#define B43_NTAB_NOISEVAR10_SIZE 256 +#define B43_NTAB_NOISEVAR11 B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */ +#define B43_NTAB_NOISEVAR11_SIZE 256 +#define B43_NTAB_C0_ESTPLT B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */ +#define B43_NTAB_C0_ESTPLT_SIZE 64 +#define B43_NTAB_C1_ESTPLT B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */ +#define B43_NTAB_C1_ESTPLT_SIZE 64 +#define B43_NTAB_C0_ADJPLT B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */ +#define B43_NTAB_C0_ADJPLT_SIZE 128 +#define B43_NTAB_C1_ADJPLT B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */ +#define B43_NTAB_C1_ADJPLT_SIZE 128 +#define B43_NTAB_C0_GAINCTL B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */ +#define B43_NTAB_C0_GAINCTL_SIZE 128 +#define B43_NTAB_C1_GAINCTL B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */ +#define B43_NTAB_C1_GAINCTL_SIZE 128 +#define B43_NTAB_C0_IQLT B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */ +#define B43_NTAB_C0_IQLT_SIZE 128 +#define B43_NTAB_C1_IQLT B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */ +#define B43_NTAB_C1_IQLT_SIZE 128 +#define B43_NTAB_C0_LOFEEDTH B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */ +#define B43_NTAB_C0_LOFEEDTH_SIZE 128 +#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ +#define B43_NTAB_C1_LOFEEDTH_SIZE 128 + +void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); + +extern const u8 b43_ntab_adjustpower0[]; +extern const u8 b43_ntab_adjustpower1[]; +extern const u16 b43_ntab_bdi[]; +extern const u32 b43_ntab_channelest[]; +extern const u8 b43_ntab_estimatepowerlt0[]; +extern const u8 b43_ntab_estimatepowerlt1[]; +extern const u8 b43_ntab_framelookup[]; +extern const u32 b43_ntab_framestruct[]; +extern const u32 b43_ntab_gainctl0[]; +extern const u32 b43_ntab_gainctl1[]; +extern const u32 b43_ntab_intlevel[]; +extern const u32 b43_ntab_iqlt0[]; +extern const u32 b43_ntab_iqlt1[]; +extern const u16 b43_ntab_loftlt0[]; +extern const u16 b43_ntab_loftlt1[]; +extern const u8 b43_ntab_mcs[]; +extern const u32 b43_ntab_noisevar10[]; +extern const u32 b43_ntab_noisevar11[]; +extern const u16 b43_ntab_pilot[]; +extern const u32 b43_ntab_pilotlt[]; +extern const u32 b43_ntab_tdi20a0[]; +extern const u32 b43_ntab_tdi20a1[]; +extern const u32 b43_ntab_tdi40a0[]; +extern const u32 b43_ntab_tdi40a1[]; +extern const u32 b43_ntab_tdtrn[]; +extern const u32 b43_ntab_tmap[]; + + +#endif /* B43_TABLES_NPHY_H_ */ diff --git a/package/b43/src/wa.c b/package/b43/src/wa.c new file mode 100644 index 0000000000..e632125cb7 --- /dev/null +++ b/package/b43/src/wa.c @@ -0,0 +1,674 @@ +/* + + Broadcom B43 wireless driver + + PHY workarounds. + + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "main.h" +#include "tables.h" +#include "phy.h" +#include "wa.h" + +static void b43_wa_papd(struct b43_wldev *dev) +{ + u16 backup; + + backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); + b43_dummy_transmission(dev); + b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); +} + +static void b43_wa_auxclipthr(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800); +} + +static void b43_wa_afcdac(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x0035, 0x03FF); + b43_phy_write(dev, 0x0036, 0x0400); +} + +static void b43_wa_txdc_offset(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051); +} + +void b43_wa_initgains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F); + if (phy->rev <= 2) + b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF); + b43_radio_write16(dev, 0x0002, 0x1FBF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + if (phy->rev <= 3) + b43_phy_write(dev, 0x002A, + (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400); + else if (phy->rev == 5) { + b43_phy_write(dev, 0x002A, + (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00); + b43_phy_write(dev, 0x00CC, 0x2121); + } + if (phy->rev >= 3) + b43_phy_write(dev, 0x00BA, 0x3ED5); +} + +static void b43_wa_divider(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100); + b43_phy_write(dev, 0x008E, 0x58C1); +} + +static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */ +{ + if (dev->phy.rev <= 2) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); + } +} + +static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */ +{ + int i; + + if (0 /* FIXME: For APHY.rev=2 this might be needed */) { + for (i = 0; i < 8; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8); + for (i = 8; i < 16; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8); + } else { + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i); + } +} + +static void b43_wa_analog(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 ofdmrev; + + ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION; + if (ofdmrev > 2) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808); + else + b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040); + } +} + +static void b43_wa_dac(struct b43_wldev *dev) +{ + if (dev->phy.analog == 1) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, + (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008); + else + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, + (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010); +} + +static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */ +{ + int i; + + if (dev->phy.type == B43_PHYTYPE_A) + for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]); + else + for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]); +} + +static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + + if (phy->type == B43_PHYTYPE_A) { + if (phy->rev == 2) + for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]); + else + for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]); + } else { + if (phy->rev == 1) + for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]); + else + for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]); + } +} + +static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ +{ + int i; + + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]); +} + +static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + + if (phy->type == B43_PHYTYPE_A) { + if (phy->rev <= 1) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, 0); + else if (phy->rev == 2) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescalea2[i]); + else if (phy->rev == 3) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescalea3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg3[i]); + } else { + if (phy->rev >= 6) { + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg2[i]); + } else { + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg1[i]); + } + } +} + +static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */ +{ + int i; + + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD, + i, b43_tab_retard[i]); +} + +static void b43_wa_txlna_gain(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000); +} + +static void b43_wa_crs_reset(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x002C, 0x0064); +} + +static void b43_wa_2060txlna_gain(struct b43_wldev *dev) +{ + b43_hf_write(dev, b43_hf_read(dev) | + B43_HF_2060W); +} + +static void b43_wa_lms(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x0055, + (b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004); +} + +static void b43_wa_mixedsignal(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3); +} + +static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + const u16 *tab; + + if (phy->type == B43_PHYTYPE_A) { + tab = b43_tab_sigmasqr1; + } else if (phy->type == B43_PHYTYPE_G) { + tab = b43_tab_sigmasqr2; + } else { + B43_WARN_ON(1); + return; + } + + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ, + i, tab[i]); + } +} + +static void b43_wa_iqadc(struct b43_wldev *dev) +{ + if (dev->phy.analog == 4) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0, + b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000); +} + +static void b43_wa_crs_ed(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19); + } else if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861); + b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271); + b43_phy_write(dev, B43_PHY_ANTDWELL, + b43_phy_read(dev, B43_PHY_ANTDWELL) + | 0x0800); + } else { + b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098); + b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070); + b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080); + b43_phy_write(dev, B43_PHY_ANTDWELL, + b43_phy_read(dev, B43_PHY_ANTDWELL) + | 0x0800); + } +} + +static void b43_wa_crs_thr(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_CRS0, + (b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000); +} + +static void b43_wa_crs_blank(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A); +} + +static void b43_wa_cck_shiftbits(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026); +} + +static void b43_wa_wrssi_offset(struct b43_wldev *dev) +{ + int i; + + if (dev->phy.rev == 1) { + for (i = 0; i < 16; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1, + i, 0x0020); + } + } else { + for (i = 0; i < 32; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI, + i, 0x0820); + } + } +} + +static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20); +} + +static void b43_wa_altagc(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D); + b43_phy_write(dev, B43_PHY_LMS, 4); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25); + } + + b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA, + (b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700); + b43_phy_write(dev, B43_PHY_OFDM(0x1A), + (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F); + b43_phy_write(dev, B43_PHY_OFDM(0x1A), + (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80); + b43_phy_write(dev, B43_PHY_ANTWRSETT, + (b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x7A, + b43_radio_read16(dev, 0x7A) | 0x0008); + b43_phy_write(dev, B43_PHY_N1P1GAIN, + (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008); + b43_phy_write(dev, B43_PHY_P1P2GAIN, + (b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600); + b43_phy_write(dev, B43_PHY_N1N2GAIN, + (b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700); + b43_phy_write(dev, B43_PHY_N1P1GAIN, + (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_N1N2GAIN, + (b43_phy_read(dev, B43_PHY_N1N2GAIN) + & ~0x000F) | 0x0007); + } + b43_phy_write(dev, B43_PHY_OFDM(0x88), + (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C); + b43_phy_write(dev, B43_PHY_OFDM(0x88), + (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200); + b43_phy_write(dev, B43_PHY_OFDM(0x96), + (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C); + b43_phy_write(dev, B43_PHY_OFDM(0x89), + (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020); + b43_phy_write(dev, B43_PHY_OFDM(0x89), + (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E); + b43_phy_write(dev, B43_PHY_OFDM(0x96), + (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00); + b43_phy_write(dev, B43_PHY_OFDM(0x81), + (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028); + b43_phy_write(dev, B43_PHY_OFDM(0x81), + (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + (b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002); + } else { + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E); + b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004); + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000); + } + } + b43_phy_write(dev, B43_PHY_DIVSRCHIDX, + (b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874); + b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_DIVP1P2GAIN, + (b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600); + b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E); + b43_phy_write(dev, B43_PHY_ANTWRSETT, + (b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E); + b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_OFDM(0x26), + b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003); + b43_phy_write(dev, B43_PHY_OFDM(0x26), + b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000); + } + b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ +} + +static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */ +{ + b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480); +} + +static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0); +} + +static void b43_wa_rssi_adc(struct b43_wldev *dev) +{ + if (dev->phy.analog == 4) + b43_phy_write(dev, 0x00DC, 0x7454); +} + +static void b43_wa_boards_a(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BU4306 && + bus->boardinfo.rev < 0x30) { + b43_phy_write(dev, 0x0010, 0xE000); + b43_phy_write(dev, 0x0013, 0x0140); + b43_phy_write(dev, 0x0014, 0x0280); + } else { + if (bus->boardinfo.type == SSB_BOARD_MP4318 && + bus->boardinfo.rev < 0x20) { + b43_phy_write(dev, 0x0013, 0x0210); + b43_phy_write(dev, 0x0014, 0x0840); + } else { + b43_phy_write(dev, 0x0013, 0x0140); + b43_phy_write(dev, 0x0014, 0x0280); + } + if (dev->phy.rev <= 4) + b43_phy_write(dev, 0x0010, 0xE000); + else + b43_phy_write(dev, 0x0010, 0x2000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040); + } +} + +static void b43_wa_boards_g(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM || + bus->boardinfo.type != SSB_BOARD_BU4306 || + bus->boardinfo.rev != 0x17) { + if (phy->rev < 2) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); + if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && + (phy->rev >= 7)) { + b43_phy_write(dev, B43_PHY_EXTG(0x11), + b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002); + } + } + } + if (bus->sprom.boardflags_lo & B43_BFL_FEM) { + b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120); + b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480); + } +} + +void b43_wa_all(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_A) { + switch (phy->rev) { + case 2: + b43_wa_papd(dev); + b43_wa_auxclipthr(dev); + b43_wa_afcdac(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_divider(dev); + b43_wa_gt(dev); + b43_wa_rssi_lt(dev); + b43_wa_analog(dev); + b43_wa_dac(dev); + b43_wa_fft(dev); + b43_wa_nft(dev); + b43_wa_rt(dev); + b43_wa_nst(dev); + b43_wa_art(dev); + b43_wa_txlna_gain(dev); + b43_wa_crs_reset(dev); + b43_wa_2060txlna_gain(dev); + b43_wa_lms(dev); + break; + case 3: + b43_wa_papd(dev); + b43_wa_mixedsignal(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + break; + case 5: + b43_wa_iqadc(dev); + case 6: + b43_wa_papd(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + break; + case 7: + b43_wa_iqadc(dev); + b43_wa_papd(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + b43_wa_rssi_adc(dev); + default: + B43_WARN_ON(1); + } + b43_wa_boards_a(dev); + } else if (phy->type == B43_PHYTYPE_G) { + switch (phy->rev) { + case 1://XXX review rev1 + b43_wa_crs_ed(dev); + b43_wa_crs_thr(dev); + b43_wa_crs_blank(dev); + b43_wa_cck_shiftbits(dev); + b43_wa_fft(dev); + b43_wa_nft(dev); + b43_wa_rt(dev); + b43_wa_nst(dev); + b43_wa_art(dev); + b43_wa_wrssi_offset(dev); + b43_wa_altagc(dev); + break; + case 2: + case 6: + case 7: + case 8: + case 9: + b43_wa_tr_ltov(dev); + b43_wa_crs_ed(dev); + b43_wa_rssi_lt(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_wrssi_offset(dev); + b43_wa_altagc(dev); + b43_wa_analog(dev); + b43_wa_txpuoff_rxpuon(dev); + break; + default: + B43_WARN_ON(1); + } + b43_wa_boards_g(dev); + } else { /* No N PHY support so far */ + B43_WARN_ON(1); + } + + b43_wa_cpll_nonpilot(dev); +} diff --git a/package/b43/src/wa.h b/package/b43/src/wa.h new file mode 100644 index 0000000000..e163c5e56e --- /dev/null +++ b/package/b43/src/wa.h @@ -0,0 +1,7 @@ +#ifndef B43_WA_H_ +#define B43_WA_H_ + +void b43_wa_initgains(struct b43_wldev *dev); +void b43_wa_all(struct b43_wldev *dev); + +#endif /* B43_WA_H_ */ diff --git a/package/b43/src/xmit.c b/package/b43/src/xmit.c index 0bd6f8a348..4014b6c827 100644 --- a/package/b43/src/xmit.c +++ b/package/b43/src/xmit.c @@ -5,7 +5,7 @@ Transmission (TX/RX) related functions. Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (C) 2005 Stefano Brivio <st3@riseup.net> + Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -30,48 +30,50 @@ #include "xmit.h" #include "phy.h" #include "dma.h" -#include "pio.h" -/* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) + +/* Extract the bitrate index out of a CCK PLCP header. */ +static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43_CCK_RATE_1MB; + return 0; case 0x14: - return B43_CCK_RATE_2MB; + return 1; case 0x37: - return B43_CCK_RATE_5MB; + return 2; case 0x6E: - return B43_CCK_RATE_11MB; + return 3; } B43_WARN_ON(1); - return 0; + return -1; } -/* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43_OFDM_RATE_54MB; + return base + 7; } B43_WARN_ON(1); - return 0; + return -1; } u8 b43_plcp_get_ratecode_cck(const u8 bitrate) @@ -177,18 +179,21 @@ static u8 b43_calc_fallback_rate(u8 bitrate) return 0; } -static void generate_txhdr_fw4(struct b43_wldev *dev, - struct b43_txhdr_fw4 *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, - u16 cookie) +/* Generate a TX data header. */ +int b43_generate_txhdr(struct b43_wldev *dev, + u8 *_txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) { + struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); + struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -198,9 +203,11 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + WARN_ON(!txctl->tx_rate); + rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); if (rate_ofdm) @@ -219,11 +226,10 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_len, - fbrate_base100kbps); + fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -235,29 +241,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, B43_WARN_ON(key_idx >= dev->max_nr_keys); key = &(dev->key[key_idx]); - B43_WARN_ON(!key->keyconf); + + if (unlikely(!key->keyconf)) { + /* This key is invalid. This might only happen + * in a short timeframe after machine resume before + * we were able to reconfigure keys. + * Drop this packet completely. Do not transmit it + * unencrypted to avoid leaking information. */ + return -ENOKEY; + } /* Hardware appends ICV. */ plcp_fragment_len += txctl->icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); - mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & - B43_TX4_MAC_KEYIDX; - mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & - B43_TX4_MAC_KEYALG; + mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & + B43_TXH_MAC_KEYIDX; + mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & + B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); iv_len = min((size_t) txctl->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), - plcp_fragment_len, rate); + if (b43_is_old_txhdr_format(dev)) { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), + plcp_fragment_len, rate); + } else { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp), + plcp_fragment_len, rate); + } b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), plcp_fragment_len, rate_fb); /* Extra Frame Types */ if (rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_FBOFDM; + extra_ft |= B43_TXH_EFT_FB_OFDM; + else + extra_ft |= B43_TXH_EFT_FB_CCK; /* Set channel radio code. Note that the micrcode ORs 0x100 to * this value before comparing it to the value in SHM, if this @@ -267,18 +288,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) - phy_ctl |= B43_TX4_PHY_OFDM; - if (dev->short_preamble) - phy_ctl |= B43_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { - case 0: - phy_ctl |= B43_TX4_PHY_ANTLAST; + phy_ctl |= B43_TXH_PHY_ENC_OFDM; + else + phy_ctl |= B43_TXH_PHY_ENC_CCK; + if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + phy_ctl |= B43_TXH_PHY_SHORTPRMBL; + + switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + case 0: /* Default */ + phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; - case 1: - phy_ctl |= B43_TX4_PHY_ANT0; + case 1: /* Antenna 0 */ + phy_ctl |= B43_TXH_PHY_ANT0; break; - case 2: - phy_ctl |= B43_TX4_PHY_ANT1; + case 2: /* Antenna 1 */ + phy_ctl |= B43_TXH_PHY_ANT1; + break; + case 3: /* Antenna 2 */ + phy_ctl |= B43_TXH_PHY_ANT2; + break; + case 4: /* Antenna 3 */ + phy_ctl |= B43_TXH_PHY_ANT3; break; default: B43_WARN_ON(1); @@ -286,14 +316,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* MAC control */ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) - mac_ctl |= B43_TX4_MAC_ACK; + mac_ctl |= B43_TXH_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) - mac_ctl |= B43_TX4_MAC_HWSEQ; + mac_ctl |= B43_TXH_MAC_HWSEQ; if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) - mac_ctl |= B43_TX4_MAC_STMSDU; + mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) - mac_ctl |= B43_TX4_MAC_5GHZ; + mac_ctl |= B43_TXH_MAC_5GHZ; + if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -302,66 +334,94 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; + struct b43_plcp_hdr6 *plcp; - rts_rate = txctl->rts_cts_rate; + WARN_ON(!txctl->rts_cts_rate); + rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, + struct ieee80211_cts *cts; + + if (b43_is_old_txhdr_format(dev)) { + cts = (struct ieee80211_cts *) + (txhdr->old_format.rts_frame); + } else { + cts = (struct ieee80211_cts *) + (txhdr->new_format.rts_frame); + } + ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, fragment_data, fragment_len, - txctl, - (struct ieee80211_cts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDCTS; + txctl, cts); + mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { - ieee80211_rts_get(dev->wl->hw, dev->wl->if_id, - fragment_data, fragment_len, txctl, - (struct ieee80211_rts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDRTS; + struct ieee80211_rts *rts; + + if (b43_is_old_txhdr_format(dev)) { + rts = (struct ieee80211_rts *) + (txhdr->old_format.rts_frame); + } else { + rts = (struct ieee80211_rts *) + (txhdr->new_format.rts_frame); + } + ieee80211_rts_get(dev->wl->hw, txctl->vif, + fragment_data, fragment_len, + txctl, rts); + mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } len += FCS_LEN; - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp), len, - rts_rate); - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp_fb), + + /* Generate the PLCP headers for the RTS/CTS frame */ + if (b43_is_old_txhdr_format(dev)) + plcp = &txhdr->old_format.rts_plcp; + else + plcp = &txhdr->new_format.rts_plcp; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, + len, rts_rate); + plcp = &txhdr->rts_plcp_fb; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, len, rts_rate_fb); - hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + + if (b43_is_old_txhdr_format(dev)) { + hdr = (struct ieee80211_hdr *) + (&txhdr->old_format.rts_frame); + } else { + hdr = (struct ieee80211_hdr *) + (&txhdr->new_format.rts_frame); + } txhdr->rts_dur_fb = hdr->duration_id; + if (rts_rate_ofdm) { - extra_ft |= B43_TX4_EFT_RTSOFDM; + extra_ft |= B43_TXH_EFT_RTS_OFDM; txhdr->phy_rate_rts = b43_plcp_get_ratecode_ofdm(rts_rate); - } else + } else { + extra_ft |= B43_TXH_EFT_RTS_CCK; txhdr->phy_rate_rts = b43_plcp_get_ratecode_cck(rts_rate); + } if (rts_rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_RTSFBOFDM; - mac_ctl |= B43_TX4_MAC_LONGFRAME; + extra_ft |= B43_TXH_EFT_RTSFB_OFDM; + else + extra_ft |= B43_TXH_EFT_RTSFB_CCK; } /* Magic cookie */ - txhdr->cookie = cpu_to_le16(cookie); + if (b43_is_old_txhdr_format(dev)) + txhdr->old_format.cookie = cpu_to_le16(cookie); + else + txhdr->new_format.cookie = cpu_to_le16(cookie); /* Apply the bitfields */ txhdr->mac_ctl = cpu_to_le32(mac_ctl); txhdr->phy_ctl = cpu_to_le16(phy_ctl); txhdr->extra_ft = extra_ft; -} -void b43_generate_txhdr(struct b43_wldev *dev, - u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie) -{ - generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, - fragment_data, fragment_len, txctl, cookie); + return 0; } static s8 b43_rssi_postprocess(struct b43_wldev *dev, @@ -384,7 +444,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, else tmp -= 3; } else { - if (dev->dev->bus->sprom.r1. + if (dev->dev->bus->sprom. boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; @@ -451,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; + u16 phytype; u8 jssi; int padding; @@ -463,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) macstat = le32_to_cpu(rxhdr->mac_status); mactime = le16_to_cpu(rxhdr->mac_time); chanstat = le16_to_cpu(rxhdr->channel); + phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (macstat & B43_RX_MAC_FCSERR) dev->wl->ieee_stats.dot11FCSErrorCount++; @@ -488,7 +550,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } wlhdr = (struct ieee80211_hdr *)(skb->data); fctl = le16_to_cpu(wlhdr->frame_control); - skb_trim(skb, skb->len - FCS_LEN); if (macstat & B43_RX_MAC_DEC) { unsigned int keyidx; @@ -521,31 +582,59 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* the next line looks wrong, but is what mac80211 wants */ status.signal = (jssi * 100) / B43_RX_MAX_SSI; if (phystat0 & B43_RX_PHYST0_OFDM) - status.rate = b43_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, + phytype == B43_PHYTYPE_A); else - status.rate = b43_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); - status.mactime = mactime; + + /* + * If monitors are present get full 64-bit timestamp. This + * code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY + * received the first symbol. + */ + if (dev->wl->radiotap_enabled) { + u16 low_mactime_now; + + b43_tsf_read(dev, &status.mactime); + low_mactime_now = status.mactime; + status.mactime = status.mactime & ~0xFFFFULL; + status.mactime += mactime; + if (low_mactime_now <= mactime) + status.mactime -= 0x10000; + status.flag |= RX_FLAG_TSFT; + } chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { case B43_PHYTYPE_A: - status.phymode = MODE_IEEE80211A; - status.freq = chanid; - status.channel = b43_freq_to_channel_a(chanid); - break; - case B43_PHYTYPE_B: - status.phymode = MODE_IEEE80211B; - status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_bg(chanid + 2400); + status.band = IEEE80211_BAND_5GHZ; + B43_WARN_ON(1); + /* FIXME: We don't really know which value the "chanid" contains. + * So the following assignment might be wrong. */ + status.freq = b43_channel_to_freq_5ghz(chanid); break; case B43_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; + /* chanid is the radio channel cookie value as used + * to tune the radio. */ status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + case B43_PHYTYPE_N: + /* chanid is the SHM channel cookie. Which is the plain + * channel number in b43. */ + if (chanstat & B43_RX_CHAN_5GHZ) { + status.band = IEEE80211_BAND_5GHZ; + status.freq = b43_freq_to_channel_5ghz(chanid); + } else { + status.band = IEEE80211_BAND_2GHZ; + status.freq = b43_freq_to_channel_2ghz(chanid); + } break; default: B43_WARN_ON(1); + goto drop; } dev->stats.last_rx = jiffies; @@ -575,10 +664,7 @@ void b43_handle_txstatus(struct b43_wldev *dev, dev->wl->ieee_stats.dot11RTSSuccessCount++; } - if (b43_using_pio(dev)) - b43_pio_handle_txstatus(dev, status); - else - b43_dma_handle_txstatus(dev, status); + b43_dma_handle_txstatus(dev, status); } /* Handle TX status report as received through DMA/PIO queues */ @@ -607,19 +693,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev, /* Stop any TX operation on the device (suspend the hardware queues) */ void b43_tx_suspend(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_freeze_txqueues(dev); - else - b43_dma_tx_suspend(dev); + b43_dma_tx_suspend(dev); } /* Resume any TX operation on the device (resume the hardware queues) */ void b43_tx_resume(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_thaw_txqueues(dev); - else - b43_dma_tx_resume(dev); + b43_dma_tx_resume(dev); } #if 0 diff --git a/package/b43/src/xmit.h b/package/b43/src/xmit.h index 03bddd2516..4176503955 100644 --- a/package/b43/src/xmit.h +++ b/package/b43/src/xmit.h @@ -19,74 +19,166 @@ _b43_declare_plcp_hdr(6); #undef _b43_declare_plcp_hdr /* TX header for v4 firmware */ -struct b43_txhdr_fw4 { - __le32 mac_ctl; /* MAC TX control */ - __le16 mac_frame_ctl; /* Copy of the FrameControl field */ +struct b43_txhdr { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl field */ __le16 tx_fes_time_norm; /* TX FES Time Normal */ - __le16 phy_ctl; /* PHY TX control */ - __le16 phy_ctl_0; /* Unused */ - __le16 phy_ctl_1; /* Unused */ - __le16 phy_ctl_rts_0; /* Unused */ - __le16 phy_ctl_rts_1; /* Unused */ - __u8 phy_rate; /* PHY rate */ - __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ - __u8 extra_ft; /* Extra Frame Types */ - __u8 chan_radio_code; /* Channel Radio Code */ - __u8 iv[16]; /* Encryption IV */ - __u8 tx_receiver[6]; /* TX Frame Receiver address */ - __le16 tx_fes_time_fb; /* TX FES Time Fallback */ - struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */ - __le16 rts_dur_fb; /* RTS fallback duration */ - struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */ - __le16 dur_fb; /* Fallback duration */ - __le16 mm_dur_time; /* Unused */ - __le16 mm_dur_time_fb; /* Unused */ - __le32 time_stamp; /* Timestamp */ - PAD_BYTES(2); - __le16 cookie; /* TX frame cookie */ - __le16 tx_status; /* TX status */ - struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */ - __u8 rts_frame[16]; /* The RTS frame (if used) */ - PAD_BYTES(2); - struct b43_plcp_hdr6 plcp; /* Main PLCP */ + __le16 phy_ctl; /* PHY TX control */ + __le16 phy_ctl1; /* PHY TX control word 1 */ + __le16 phy_ctl1_fb; /* PHY TX control word 1 for fallback rates */ + __le16 phy_ctl1_rts; /* PHY TX control word 1 RTS */ + __le16 phy_ctl1_rts_fb; /* PHY TX control word 1 RTS for fallback rates */ + __u8 phy_rate; /* PHY rate */ + __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ + __u8 extra_ft; /* Extra Frame Types */ + __u8 chan_radio_code; /* Channel Radio Code */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP header */ + __le16 dur_fb; /* Fallback duration */ + __le16 mimo_modelen; /* MIMO mode length */ + __le16 mimo_ratelen_fb; /* MIMO fallback rate length */ + __le32 timeout; /* Timeout */ + + union { + /* The new r410 format. */ + struct { + __le16 mimo_antenna; /* MIMO antenna select */ + __le16 preload_size; /* Preload size */ + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP header */ + } new_format __attribute__ ((__packed__)); + + /* The old r351 format. */ + struct { + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP header */ + } old_format __attribute__ ((__packed__)); + + } __attribute__ ((__packed__)); } __attribute__ ((__packed__)); /* MAC TX control */ -#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ -#define B43_TX4_MAC_KEYIDX_SHIFT 20 -#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ -#define B43_TX4_MAC_KEYALG_SHIFT 16 -#define B43_TX4_MAC_LIFETIME 0x00001000 -#define B43_TX4_MAC_FRAMEBURST 0x00000800 -#define B43_TX4_MAC_SENDCTS 0x00000400 -#define B43_TX4_MAC_AMPDU 0x00000300 -#define B43_TX4_MAC_AMPDU_SHIFT 8 -#define B43_TX4_MAC_5GHZ 0x00000080 -#define B43_TX4_MAC_IGNPMQ 0x00000020 -#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ -#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ -#define B43_TX4_MAC_SENDRTS 0x00000004 -#define B43_TX4_MAC_LONGFRAME 0x00000002 -#define B43_TX4_MAC_ACK 0x00000001 +#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */ +#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43_TXH_MAC_KEYIDX_SHIFT 20 +#define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43_TXH_MAC_KEYALG_SHIFT 16 +#define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */ +#define B43_TXH_MAC_RIFS 0x00004000 /* Use RIFS */ +#define B43_TXH_MAC_LIFETIME 0x00002000 /* Lifetime */ +#define B43_TXH_MAC_FRAMEBURST 0x00001000 /* Frameburst */ +#define B43_TXH_MAC_SENDCTS 0x00000800 /* Send CTS-to-self */ +#define B43_TXH_MAC_AMPDU 0x00000600 /* AMPDU status */ +#define B43_TXH_MAC_AMPDU_MPDU 0x00000000 /* Regular MPDU, not an AMPDU */ +#define B43_TXH_MAC_AMPDU_FIRST 0x00000200 /* First MPDU or AMPDU */ +#define B43_TXH_MAC_AMPDU_INTER 0x00000400 /* Intermediate MPDU or AMPDU */ +#define B43_TXH_MAC_AMPDU_LAST 0x00000600 /* Last (or only) MPDU of AMPDU */ +#define B43_TXH_MAC_40MHZ 0x00000100 /* Use 40 MHz bandwidth */ +#define B43_TXH_MAC_5GHZ 0x00000080 /* 5GHz band */ +#define B43_TXH_MAC_DFCS 0x00000040 /* DFCS */ +#define B43_TXH_MAC_IGNPMQ 0x00000020 /* Ignore PMQ */ +#define B43_TXH_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ +#define B43_TXH_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43_TXH_MAC_SENDRTS 0x00000004 /* Send RTS */ +#define B43_TXH_MAC_LONGFRAME 0x00000002 /* Long frame */ +#define B43_TXH_MAC_ACK 0x00000001 /* Immediate ACK */ /* Extra Frame Types */ -#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */ -#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ -#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ +#define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */ +#define B43_TXH_EFT_FB_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */ +#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */ +#define B43_TXH_EFT_FB_N 0x03 /* N */ +#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */ +#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */ +#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */ +#define B43_TXH_EFT_RTS_N 0x0C /* N */ +#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */ +#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */ +#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */ +#define B43_TXH_EFT_RTSFB_N 0x30 /* N */ /* PHY TX control word */ -#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ -#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ -#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */ -#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ -#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ -#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ - -void b43_generate_txhdr(struct b43_wldev *dev, - u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie); +#define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */ +#define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */ +#define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */ +#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */ +#define B43_TXH_PHY_ENC_N 0x0003 /* N */ +#define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43_TXH_PHY_ANT1 0x0040 /* Use antenna 1 */ +#define B43_TXH_PHY_ANT01AUTO 0x00C0 /* Use antenna 0/1 auto */ +#define B43_TXH_PHY_ANT2 0x0100 /* Use antenna 2 */ +#define B43_TXH_PHY_ANT3 0x0200 /* Use antenna 3 */ +#define B43_TXH_PHY_TXPWR 0xFC00 /* TX power */ +#define B43_TXH_PHY_TXPWR_SHIFT 10 + +/* PHY TX control word 1 */ +#define B43_TXH_PHY1_BW 0x0007 /* Bandwidth */ +#define B43_TXH_PHY1_BW_10 0x0000 /* 10 MHz */ +#define B43_TXH_PHY1_BW_10U 0x0001 /* 10 MHz upper */ +#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */ +#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */ +#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */ +#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */ +#define B43_TXH_PHY1_MODE 0x0038 /* Mode */ +#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */ +#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */ +#define B43_TXH_PHY1_MODE_STBC 0x0010 /* STBC */ +#define B43_TXH_PHY1_MODE_SDM 0x0018 /* SDM */ +#define B43_TXH_PHY1_CRATE 0x0700 /* Coding rate */ +#define B43_TXH_PHY1_CRATE_1_2 0x0000 /* 1/2 */ +#define B43_TXH_PHY1_CRATE_2_3 0x0100 /* 2/3 */ +#define B43_TXH_PHY1_CRATE_3_4 0x0200 /* 3/4 */ +#define B43_TXH_PHY1_CRATE_4_5 0x0300 /* 4/5 */ +#define B43_TXH_PHY1_CRATE_5_6 0x0400 /* 5/6 */ +#define B43_TXH_PHY1_CRATE_7_8 0x0600 /* 7/8 */ +#define B43_TXH_PHY1_MODUL 0x3800 /* Modulation scheme */ +#define B43_TXH_PHY1_MODUL_BPSK 0x0000 /* BPSK */ +#define B43_TXH_PHY1_MODUL_QPSK 0x0800 /* QPSK */ +#define B43_TXH_PHY1_MODUL_QAM16 0x1000 /* QAM16 */ +#define B43_TXH_PHY1_MODUL_QAM64 0x1800 /* QAM64 */ +#define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */ + + +/* r351 firmware compatibility stuff. */ +static inline +bool b43_is_old_txhdr_format(struct b43_wldev *dev) +{ + return (dev->fw.rev <= 351); +} + +static inline +size_t b43_txhdr_size(struct b43_wldev *dev) +{ + if (b43_is_old_txhdr_format(dev)) + return 100 + sizeof(struct b43_plcp_hdr6); + return 104 + sizeof(struct b43_plcp_hdr6); +} + + +int b43_generate_txhdr(struct b43_wldev *dev, + u8 * txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -142,49 +234,56 @@ struct b43_rxhdr_fw4 { } __attribute__ ((__packed__)); /* PHY RX Status 0 */ -#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ -#define B43_RX_PHYST0_PLCPHCF 0x0200 -#define B43_RX_PHYST0_PLCPFV 0x0100 -#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */ +#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ +#define B43_RX_PHYST0_PLCPHCF 0x0200 +#define B43_RX_PHYST0_PLCPFV 0x0100 +#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */ #define B43_RX_PHYST0_LCRS 0x0040 -#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */ -#define B43_RX_PHYST0_UNSRATE 0x0010 +#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */ +#define B43_RX_PHYST0_UNSRATE 0x0010 #define B43_RX_PHYST0_CLIP 0x000C #define B43_RX_PHYST0_CLIP_SHIFT 2 -#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */ -#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ -#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ -#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ -#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ +#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */ +#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ +#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ +#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ +#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ /* PHY RX Status 2 */ -#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ +#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ #define B43_RX_PHYST2_LNAG_SHIFT 14 -#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ +#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ #define B43_RX_PHYST2_PNAG_SHIFT 10 -#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */ +#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */ /* PHY RX Status 3 */ -#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ +#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ #define B43_RX_PHYST3_DIGG_SHIFT 11 -#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */ +#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */ /* MAC RX Status */ -#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */ -#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */ -#define B43_RX_MAC_KEYIDX_SHIFT 5 -#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */ -#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */ -#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ -#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */ -#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */ +#define B43_RX_MAC_RXST_VALID 0x01000000 /* PHY RXST valid */ +#define B43_RX_MAC_TKIP_MICERR 0x00100000 /* TKIP MIC error */ +#define B43_RX_MAC_TKIP_MICATT 0x00080000 /* TKIP MIC attempted */ +#define B43_RX_MAC_AGGTYPE 0x00060000 /* Aggregation type */ +#define B43_RX_MAC_AGGTYPE_SHIFT 17 +#define B43_RX_MAC_AMSDU 0x00010000 /* A-MSDU mask */ +#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon sent flag */ +#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */ +#define B43_RX_MAC_KEYIDX_SHIFT 5 +#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */ +#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */ +#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ +#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */ +#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */ /* RX channel */ -#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */ -#define B43_RX_CHAN_GAIN_SHIFT 10 -#define B43_RX_CHAN_ID 0x03FC /* Channel ID */ -#define B43_RX_CHAN_ID_SHIFT 2 -#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */ +#define B43_RX_CHAN_40MHZ 0x1000 /* 40 Mhz channel width */ +#define B43_RX_CHAN_5GHZ 0x0800 /* 5 Ghz band */ +#define B43_RX_CHAN_ID 0x07F8 /* Channel ID */ +#define B43_RX_CHAN_ID_SHIFT 3 +#define B43_RX_CHAN_PHYTYPE 0x0007 /* PHY type */ + u8 b43_plcp_get_ratecode_cck(const u8 bitrate); u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate); diff --git a/package/hostapd/files/default.config b/package/hostapd/files/default.config index 700217dada..f383e116cd 100644 --- a/package/hostapd/files/default.config +++ b/package/hostapd/files/default.config @@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y #CONFIG_DRIVER_PRISM54=y # Driver interface for drivers using Devicescape IEEE 802.11 stack -CONFIG_DRIVER_DEVICESCAPE=y +#CONFIG_DRIVER_DEVICESCAPE=y # Currently, driver_devicescape.c build requires some additional parameters # to be able to include some of the kernel header files. Following lines can # be used to set these (WIRELESS_DEV must point to the root directory of the diff --git a/package/hostapd/files/mini.config b/package/hostapd/files/mini.config index a2f3f62bba..d1ab057ccc 100644 --- a/package/hostapd/files/mini.config +++ b/package/hostapd/files/mini.config @@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y #CONFIG_DRIVER_PRISM54=y # Driver interface for drivers using Devicescape IEEE 802.11 stack -CONFIG_DRIVER_DEVICESCAPE=y +#CONFIG_DRIVER_DEVICESCAPE=y # Currently, driver_devicescape.c build requires some additional parameters # to be able to include some of the kernel header files. Following lines can # be used to set these (WIRELESS_DEV must point to the root directory of the diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index 723ba77be5..9d8320e180 100644 --- a/package/mac80211/Makefile +++ b/package/mac80211/Makefile @@ -28,11 +28,12 @@ define KernelPackage/mac80211/description Linux 802.11 Wireless Networking Stack endef -CONFOPTS:=MAC80211 CFG80211 NL80211 +CONFOPTS:=MAC80211 CFG80211 NL80211 MAC80211_RC_DEFAULT_PID MAC80211_RC_PID BUILDFLAGS:= \ - $(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) -DCONFIG_MAC80211_RCSIMPLE=1) \ - $(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS) + $(foreach opt,$(CONFOPTS),-DCONFIG_$(opt)) \ + $(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS) \ + -D__CONFIG_MAC80211_RC_DEFAULT=pid MAKE_OPTS:= \ CROSS_COMPILE="$(TARGET_CROSS)" \ @@ -40,7 +41,7 @@ MAKE_OPTS:= \ EXTRA_CFLAGS="$(BUILDFLAGS)" \ $(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \ CONFIG_NL80211=y \ - CONFIG_MAC80211_RCSIMPLE=y \ + CONFIG_MAC80211_RC_PID=y \ CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \ LINUXINCLUDE="-I$(PKG_BUILD_DIR)/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \ diff --git a/package/mac80211/patches/000-mac80211_update.patch b/package/mac80211/patches/000-mac80211_update.patch deleted file mode 100644 index 7a1a1e271b..0000000000 --- a/package/mac80211/patches/000-mac80211_update.patch +++ /dev/null @@ -1,933 +0,0 @@ -Index: mac80211/include/linux/ieee80211.h -=================================================================== ---- mac80211.orig/include/linux/ieee80211.h 2007-11-11 15:45:23.153490050 +0100 -+++ mac80211/include/linux/ieee80211.h 2007-11-11 15:45:30.417904025 +0100 -@@ -81,18 +81,18 @@ - - - /* miscellaneous IEEE 802.11 constants */ --#define IEEE80211_MAX_FRAG_THRESHOLD 2346 --#define IEEE80211_MAX_RTS_THRESHOLD 2347 -+#define IEEE80211_MAX_FRAG_THRESHOLD 2352 -+#define IEEE80211_MAX_RTS_THRESHOLD 2353 - #define IEEE80211_MAX_AID 2007 - #define IEEE80211_MAX_TIM_LEN 251 --#define IEEE80211_MAX_DATA_LEN 2304 - /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - 6.2.1.1.2. - -- The figure in section 7.1.2 suggests a body size of up to 2312 -- bytes is allowed, which is a bit confusing, I suspect this -- represents the 2304 bytes of real data, plus a possible 8 bytes of -- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ -+ 802.11e clarifies the figure in section 7.1.2. The frame body is -+ up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ -+#define IEEE80211_MAX_DATA_LEN 2304 -+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ -+#define IEEE80211_MAX_FRAME_LEN 2352 - - #define IEEE80211_MAX_SSID_LEN 32 - -Index: mac80211/include/linux/nl80211.h -=================================================================== ---- mac80211.orig/include/linux/nl80211.h 2007-11-11 15:45:23.161490506 +0100 -+++ mac80211/include/linux/nl80211.h 2007-11-11 15:45:30.421904255 +0100 -@@ -25,7 +25,7 @@ - * either a dump request on a %NL80211_ATTR_WIPHY or a specific get - * on an %NL80211_ATTR_IFINDEX is supported. - * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires -- %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. -+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. - * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response - * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, - * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also -Index: mac80211/include/net/mac80211.h -=================================================================== ---- mac80211.orig/include/net/mac80211.h 2007-11-11 15:45:23.169490961 +0100 -+++ mac80211/include/net/mac80211.h 2007-11-11 15:45:30.429904707 +0100 -@@ -706,11 +706,16 @@ - * - * @queues: number of available hardware transmit queues for - * data packets. WMM/QoS requires at least four. -+ * -+ * @rate_control_algorithm: rate control algorithm for this hardware. -+ * If unset (NULL), the default algorithm will be used. Must be -+ * set before calling ieee80211_register_hw(). - */ - struct ieee80211_hw { - struct ieee80211_conf conf; - struct wiphy *wiphy; - struct workqueue_struct *workqueue; -+ const char *rate_control_algorithm; - void *priv; - u32 flags; - unsigned int extra_tx_headroom; -@@ -936,27 +941,11 @@ - * and remove_interface calls, i.e. while the interface with the - * given local_address is enabled. - * -- * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card -- * to pass unencrypted EAPOL-Key frames even when encryption is -- * configured. If the wlan card does not require such a configuration, -- * this function pointer can be set to NULL. -- * -- * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be -- * authorized (@authorized=1) or unauthorized (=0). This function can be -- * used if the wlan hardware or low-level driver implements PAE. -- * mac80211 will filter frames based on authorization state in any case, -- * so this function pointer can be NULL if low-level driver does not -- * require event notification about port state changes. -- * - * @hw_scan: Ask the hardware to service the scan request, no need to start - * the scan state machine in stack. - * - * @get_stats: return low-level statistics - * -- * @set_privacy_invoked: For devices that generate their own beacons and probe -- * response or association responses this updates the state of privacy_invoked -- * returns 0 for success or an error number. -- * - * @get_sequence_counter: For devices that have internal sequence counters this - * callback allows mac80211 to access the current value of a counter. - * This callback seems not well-defined, tell us if you need it. -@@ -1029,14 +1018,9 @@ - int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, - const u8 *local_address, const u8 *address, - struct ieee80211_key_conf *key); -- int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x); -- int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr, -- int authorized); - int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); - int (*get_stats)(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats); -- int (*set_privacy_invoked)(struct ieee80211_hw *hw, -- int privacy_invoked); - int (*get_sequence_counter)(struct ieee80211_hw *hw, - u8* addr, u8 keyidx, u8 txrx, - u32* iv32, u16* iv16); -Index: mac80211/net/mac80211/aes_ccm.c -=================================================================== ---- mac80211.orig/net/mac80211/aes_ccm.c 2007-11-11 15:45:23.177491419 +0100 -+++ mac80211/net/mac80211/aes_ccm.c 2007-11-11 15:45:30.433904936 +0100 -@@ -7,10 +7,10 @@ - * published by the Free Software Foundation. - */ - -+#include <linux/kernel.h> - #include <linux/types.h> - #include <linux/crypto.h> - #include <linux/err.h> --#include <asm/scatterlist.h> - - #include <net/mac80211.h> - #include "ieee80211_key.h" -@@ -63,7 +63,7 @@ - s_0 = scratch + AES_BLOCK_LEN; - e = scratch + 2 * AES_BLOCK_LEN; - -- num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; -+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); - last_len = data_len % AES_BLOCK_LEN; - aes_ccm_prepare(tfm, b_0, aad, b, s_0, b); - -@@ -102,7 +102,7 @@ - s_0 = scratch + AES_BLOCK_LEN; - a = scratch + 2 * AES_BLOCK_LEN; - -- num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; -+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); - last_len = data_len % AES_BLOCK_LEN; - aes_ccm_prepare(tfm, b_0, aad, b, s_0, a); - -Index: mac80211/net/mac80211/ieee80211.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:45:23.185491871 +0100 -+++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:45:30.437905164 +0100 -@@ -1061,7 +1061,8 @@ - ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); - ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); - -- result = ieee80211_init_rate_ctrl_alg(local, NULL); -+ result = ieee80211_init_rate_ctrl_alg(local, -+ hw->rate_control_algorithm); - if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize rate control " - "algorithm\n", wiphy_name(local->hw.wiphy)); -@@ -1222,8 +1223,17 @@ - - BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); - -+#ifdef CONFIG_MAC80211_RCSIMPLE -+ ret = ieee80211_rate_control_register(&mac80211_rcsimple); -+ if (ret) -+ return ret; -+#endif -+ - ret = ieee80211_wme_register(); - if (ret) { -+#ifdef CONFIG_MAC80211_RCSIMPLE -+ ieee80211_rate_control_unregister(&mac80211_rcsimple); -+#endif - printk(KERN_DEBUG "ieee80211_init: failed to " - "initialize WME (err=%d)\n", ret); - return ret; -@@ -1237,6 +1247,10 @@ - - static void __exit ieee80211_exit(void) - { -+#ifdef CONFIG_MAC80211_RCSIMPLE -+ ieee80211_rate_control_unregister(&mac80211_rcsimple); -+#endif -+ - ieee80211_wme_unregister(); - ieee80211_debugfs_netdev_exit(); - } -Index: mac80211/net/mac80211/ieee80211_i.h -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:45:23.189492100 +0100 -+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:45:30.441905395 +0100 -@@ -232,6 +232,7 @@ - #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) - #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) - #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) -+#define IEEE80211_STA_PRIVACY_INVOKED BIT(13) - struct ieee80211_if_sta { - enum { - IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, -@@ -261,7 +262,6 @@ - unsigned long request; - struct sk_buff_head skb_queue; - -- int key_management_enabled; - unsigned long last_probe; - - #define IEEE80211_AUTH_ALG_OPEN BIT(0) -Index: mac80211/net/mac80211/ieee80211_ioctl.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:45:23.197492559 +0100 -+++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:45:30.441905395 +0100 -@@ -305,9 +305,12 @@ - ((chan->chan == channel) || (chan->freq == freq))) { - local->oper_channel = chan; - local->oper_hw_mode = mode; -- set++; -+ set = 1; -+ break; - } - } -+ if (set) -+ break; - } - - if (set) { -@@ -507,10 +510,11 @@ - - static int ieee80211_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, -- struct iw_point *data, char *extra) -+ union iwreq_data *wrqu, char *extra) - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct iw_scan_req *req = NULL; - u8 *ssid = NULL; - size_t ssid_len = 0; - -@@ -535,6 +539,14 @@ - return -EOPNOTSUPP; - } - -+ /* if SSID was specified explicitly then use that */ -+ if (wrqu->data.length == sizeof(struct iw_scan_req) && -+ wrqu->data.flags & IW_SCAN_THIS_ESSID) { -+ req = (struct iw_scan_req *)extra; -+ ssid = req->essid; -+ ssid_len = req->essid_len; -+ } -+ - return ieee80211_sta_req_scan(dev, ssid, ssid_len); - } - -@@ -621,22 +633,35 @@ - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - bool need_reconfig = 0; -+ u8 new_power_level; - - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) - return -EINVAL; - if (data->txpower.flags & IW_TXPOW_RANGE) - return -EINVAL; -- if (!data->txpower.fixed) -- return -EINVAL; - -- if (local->hw.conf.power_level != data->txpower.value) { -- local->hw.conf.power_level = data->txpower.value; -+ if (data->txpower.fixed) { -+ new_power_level = data->txpower.value; -+ } else { -+ /* Automatic power level. Get the px power from the current -+ * channel. */ -+ struct ieee80211_channel* chan = local->oper_channel; -+ if (!chan) -+ return -EINVAL; -+ -+ new_power_level = chan->power_level; -+ } -+ -+ if (local->hw.conf.power_level != new_power_level) { -+ local->hw.conf.power_level = new_power_level; - need_reconfig = 1; - } -+ - if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { - local->hw.conf.radio_enabled = !(data->txpower.disabled); - need_reconfig = 1; - } -+ - if (need_reconfig) { - ieee80211_hw_config(local); - /* The return value of hw_config is not of big interest here, -@@ -904,7 +929,6 @@ - struct iw_request_info *info, - struct iw_param *data, char *extra) - { -- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - -@@ -914,18 +938,21 @@ - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_WPA_ENABLED: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: -- break; - case IW_AUTH_KEY_MGMT: -+ break; -+ case IW_AUTH_PRIVACY_INVOKED: - if (sdata->type != IEEE80211_IF_TYPE_STA) - ret = -EINVAL; - else { -+ sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; - /* -- * Key management was set by wpa_supplicant, -- * we only need this to associate to a network -- * that has privacy enabled regardless of not -- * having a key. -+ * Privacy invoked by wpa_supplicant, store the -+ * value and allow associating to a protected -+ * network without having a key up front. - */ -- sdata->u.sta.key_management_enabled = !!data->value; -+ if (data->value) -+ sdata->u.sta.flags |= -+ IEEE80211_STA_PRIVACY_INVOKED; - } - break; - case IW_AUTH_80211_AUTH_ALG: -@@ -935,11 +962,6 @@ - else - ret = -EOPNOTSUPP; - break; -- case IW_AUTH_PRIVACY_INVOKED: -- if (local->ops->set_privacy_invoked) -- ret = local->ops->set_privacy_invoked( -- local_to_hw(local), data->value); -- break; - default: - ret = -EOPNOTSUPP; - break; -Index: mac80211/net/mac80211/ieee80211_rate.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:45:23.205493011 +0100 -+++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:45:30.441905395 +0100 -@@ -25,13 +25,25 @@ - { - struct rate_control_alg *alg; - -+ if (!ops->name) -+ return -EINVAL; -+ -+ mutex_lock(&rate_ctrl_mutex); -+ list_for_each_entry(alg, &rate_ctrl_algs, list) { -+ if (!strcmp(alg->ops->name, ops->name)) { -+ /* don't register an algorithm twice */ -+ WARN_ON(1); -+ return -EALREADY; -+ } -+ } -+ - alg = kzalloc(sizeof(*alg), GFP_KERNEL); - if (alg == NULL) { -+ mutex_unlock(&rate_ctrl_mutex); - return -ENOMEM; - } - alg->ops = ops; - -- mutex_lock(&rate_ctrl_mutex); - list_add_tail(&alg->list, &rate_ctrl_algs); - mutex_unlock(&rate_ctrl_mutex); - -@@ -61,9 +73,12 @@ - struct rate_control_alg *alg; - struct rate_control_ops *ops = NULL; - -+ if (!name) -+ return NULL; -+ - mutex_lock(&rate_ctrl_mutex); - list_for_each_entry(alg, &rate_ctrl_algs, list) { -- if (!name || !strcmp(alg->ops->name, name)) -+ if (!strcmp(alg->ops->name, name)) - if (try_module_get(alg->ops->module)) { - ops = alg->ops; - break; -@@ -80,9 +95,12 @@ - { - struct rate_control_ops *ops; - -+ if (!name) -+ name = "simple"; -+ - ops = ieee80211_try_rate_control_ops_get(name); - if (!ops) { -- request_module("rc80211_%s", name ? name : "default"); -+ request_module("rc80211_%s", name); - ops = ieee80211_try_rate_control_ops_get(name); - } - return ops; -Index: mac80211/net/mac80211/ieee80211_rate.h -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:45:23.213493469 +0100 -+++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:45:30.445905621 +0100 -@@ -65,6 +65,9 @@ - struct kref kref; - }; - -+/* default 'simple' algorithm */ -+extern struct rate_control_ops mac80211_rcsimple; -+ - int ieee80211_rate_control_register(struct rate_control_ops *ops); - void ieee80211_rate_control_unregister(struct rate_control_ops *ops); - -Index: mac80211/net/mac80211/ieee80211_sta.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:45:23.217493699 +0100 -+++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:46:32.885463850 +0100 -@@ -12,7 +12,6 @@ - */ - - /* TODO: -- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs - * order BSS list by RSSI(?) ("quality of AP") - * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, - * SSID) -@@ -61,7 +60,8 @@ - static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, - u8 *ssid, size_t ssid_len); - static struct ieee80211_sta_bss * --ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid); -+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, -+ u8 *ssid, u8 ssid_len); - static void ieee80211_rx_bss_put(struct net_device *dev, - struct ieee80211_sta_bss *bss); - static int ieee80211_sta_find_ibss(struct net_device *dev, -@@ -108,14 +108,11 @@ - u8 wmm_param_len; - }; - --enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 }; -- --static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, -- struct ieee802_11_elems *elems) -+static void ieee802_11_parse_elems(u8 *start, size_t len, -+ struct ieee802_11_elems *elems) - { - size_t left = len; - u8 *pos = start; -- int unknown = 0; - - memset(elems, 0, sizeof(*elems)); - -@@ -126,15 +123,8 @@ - elen = *pos++; - left -= 2; - -- if (elen > left) { --#if 0 -- if (net_ratelimit()) -- printk(KERN_DEBUG "IEEE 802.11 element parse " -- "failed (id=%d elen=%d left=%d)\n", -- id, elen, left); --#endif -- return ParseFailed; -- } -+ if (elen > left) -+ return; - - switch (id) { - case WLAN_EID_SSID: -@@ -201,28 +191,15 @@ - elems->ext_supp_rates_len = elen; - break; - default: --#if 0 -- printk(KERN_DEBUG "IEEE 802.11 element parse ignored " -- "unknown element (id=%d elen=%d)\n", -- id, elen); --#endif -- unknown++; - break; - } - - left -= elen; - pos += elen; - } -- -- /* Do not trigger error if left == 1 as Apple Airport base stations -- * send AssocResps that are one spurious byte too long. */ -- -- return unknown ? ParseUnknown : ParseOK; - } - - -- -- - static int ecw2cw(int ecw) - { - int cw = 1; -@@ -426,7 +403,9 @@ - if (sdata->type != IEEE80211_IF_TYPE_STA) - return; - -- bss = ieee80211_rx_bss_get(dev, ifsta->bssid); -+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, -+ local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len); - if (bss) { - if (bss->has_erp_value) - ieee80211_handle_erp_ie(dev, bss->erp_value); -@@ -571,7 +550,8 @@ - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | - WLAN_CAPABILITY_SHORT_PREAMBLE; - } -- bss = ieee80211_rx_bss_get(dev, ifsta->bssid); -+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len); - if (bss) { - if (bss->capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; -@@ -719,24 +699,30 @@ - static int ieee80211_privacy_mismatch(struct net_device *dev, - struct ieee80211_if_sta *ifsta) - { -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; -- int res = 0; -+ int bss_privacy; -+ int wep_privacy; -+ int privacy_invoked; - -- if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) || -- ifsta->key_management_enabled) -+ if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) - return 0; - -- bss = ieee80211_rx_bss_get(dev, ifsta->bssid); -+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len); - if (!bss) - return 0; - -- if (ieee80211_sta_wep_configured(dev) != -- !!(bss->capability & WLAN_CAPABILITY_PRIVACY)) -- res = 1; -+ bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); -+ wep_privacy = !!ieee80211_sta_wep_configured(dev); -+ privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); - - ieee80211_rx_bss_put(dev, bss); - -- return res; -+ if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) -+ return 0; -+ -+ return 1; - } - - -@@ -920,12 +906,7 @@ - - printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name); - pos = mgmt->u.auth.variable; -- if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) -- == ParseFailed) { -- printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n", -- dev->name); -- return; -- } -+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) { - printk(KERN_DEBUG "%s: no challenge IE in shared key auth " - "frame\n", dev->name); -@@ -1214,12 +1195,7 @@ - } - - pos = mgmt->u.assoc_resp.variable; -- if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) -- == ParseFailed) { -- printk(KERN_DEBUG "%s: failed to parse AssocResp\n", -- dev->name); -- return; -- } -+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - - if (!elems.supp_rates) { - printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", -@@ -1231,7 +1207,9 @@ - * update our stored copy */ - if (elems.erp_info && elems.erp_info_len >= 1) { - struct ieee80211_sta_bss *bss -- = ieee80211_rx_bss_get(dev, ifsta->bssid); -+ = ieee80211_rx_bss_get(dev, ifsta->bssid, -+ local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len); - if (bss) { - bss->erp_value = elems.erp_info[0]; - bss->has_erp_value = 1; -@@ -1261,7 +1239,9 @@ - " AP\n", dev->name); - return; - } -- bss = ieee80211_rx_bss_get(dev, ifsta->bssid); -+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid, -+ local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len); - if (bss) { - sta->last_rssi = bss->rssi; - sta->last_signal = bss->signal; -@@ -1337,7 +1317,8 @@ - - - static struct ieee80211_sta_bss * --ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) -+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, -+ u8 *ssid, u8 ssid_len) - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; -@@ -1348,6 +1329,11 @@ - atomic_inc(&bss->users); - atomic_inc(&bss->users); - memcpy(bss->bssid, bssid, ETH_ALEN); -+ bss->channel = channel; -+ if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { -+ memcpy(bss->ssid, ssid, ssid_len); -+ bss->ssid_len = ssid_len; -+ } - - spin_lock_bh(&local->sta_bss_lock); - /* TODO: order by RSSI? */ -@@ -1359,7 +1345,8 @@ - - - static struct ieee80211_sta_bss * --ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid) -+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, -+ u8 *ssid, u8 ssid_len) - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; -@@ -1367,7 +1354,10 @@ - spin_lock_bh(&local->sta_bss_lock); - bss = local->sta_bss_hash[STA_HASH(bssid)]; - while (bss) { -- if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { -+ if (!memcmp(bss->bssid, bssid, ETH_ALEN) && -+ bss->channel == channel && -+ bss->ssid_len == ssid_len && -+ (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { - atomic_inc(&bss->users); - break; - } -@@ -1429,7 +1419,7 @@ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee802_11_elems elems; - size_t baselen; -- int channel, invalid = 0, clen; -+ int channel, clen; - struct ieee80211_sta_bss *bss; - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -@@ -1473,9 +1463,7 @@ - #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - } - -- if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, -- &elems) == ParseFailed) -- invalid = 1; -+ ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && - memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && -@@ -1533,9 +1521,11 @@ - else - channel = rx_status->channel; - -- bss = ieee80211_rx_bss_get(dev, mgmt->bssid); -+ bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel, -+ elems.ssid, elems.ssid_len); - if (!bss) { -- bss = ieee80211_rx_bss_add(dev, mgmt->bssid); -+ bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, -+ elems.ssid, elems.ssid_len); - if (!bss) - return; - } else { -@@ -1561,10 +1551,6 @@ - - bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); - bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); -- if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) { -- memcpy(bss->ssid, elems.ssid, elems.ssid_len); -- bss->ssid_len = elems.ssid_len; -- } - - bss->supp_rates_len = 0; - if (elems.supp_rates) { -@@ -1635,7 +1621,6 @@ - - - bss->hw_mode = rx_status->phymode; -- bss->channel = channel; - bss->freq = rx_status->freq; - if (channel != rx_status->channel && - (bss->hw_mode == MODE_IEEE80211G || -@@ -1695,9 +1680,7 @@ - if (baselen > len) - return; - -- if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, -- &elems) == ParseFailed) -- return; -+ ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - if (elems.erp_info && elems.erp_info_len >= 1) - ieee80211_handle_erp_ie(dev, elems.erp_info[0]); -@@ -2098,7 +2081,8 @@ - { - int tmp, hidden_ssid; - -- if (!memcmp(ifsta->ssid, ssid, ssid_len)) -+ if (ssid_len == ifsta->ssid_len && -+ !memcmp(ifsta->ssid, ssid, ssid_len)) - return 1; - - if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) -@@ -2357,7 +2341,7 @@ - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; -- struct ieee80211_sub_if_data *sdata; -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; - u8 bssid[ETH_ALEN], *pos; - int i; -@@ -2379,18 +2363,17 @@ - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n", - dev->name, MAC_ARG(bssid)); - -- bss = ieee80211_rx_bss_add(dev, bssid); -+ bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel, -+ sdata->u.sta.ssid, sdata->u.sta.ssid_len); - if (!bss) - return -ENOMEM; - -- sdata = IEEE80211_DEV_TO_SUB_IF(dev); - mode = local->oper_hw_mode; - - if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 100; - bss->beacon_int = local->hw.conf.beacon_int; - bss->hw_mode = local->hw.conf.phymode; -- bss->channel = local->hw.conf.channel; - bss->freq = local->hw.conf.freq; - bss->last_update = jiffies; - bss->capability = WLAN_CAPABILITY_IBSS; -@@ -2448,7 +2431,8 @@ - MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid)); - #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && -- (bss = ieee80211_rx_bss_get(dev, bssid))) { -+ (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel, -+ ifsta->ssid, ifsta->ssid_len))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT - " based on configured SSID\n", - dev->name, MAC_ARG(bssid)); -Index: mac80211/net/mac80211/Kconfig -=================================================================== ---- mac80211.orig/net/mac80211/Kconfig 2007-11-11 15:45:23.225494151 +0100 -+++ mac80211/net/mac80211/Kconfig 2007-11-11 15:45:30.449905846 +0100 -@@ -13,6 +13,18 @@ - This option enables the hardware independent IEEE 802.11 - networking stack. - -+config MAC80211_RCSIMPLE -+ bool "'simple' rate control algorithm" if EMBEDDED -+ default y -+ depends on MAC80211 -+ help -+ This option allows you to turn off the 'simple' rate -+ control algorithm in mac80211. If you do turn it off, -+ you absolutely need another rate control algorithm. -+ -+ Say Y unless you know you will have another algorithm -+ available. -+ - config MAC80211_LEDS - bool "Enable LED triggers" - depends on MAC80211 && LEDS_TRIGGERS -Index: mac80211/net/mac80211/Makefile -=================================================================== ---- mac80211.orig/net/mac80211/Makefile 2007-11-11 15:45:23.233494609 +0100 -+++ mac80211/net/mac80211/Makefile 2007-11-11 15:45:30.449905846 +0100 -@@ -1,8 +1,9 @@ --obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o -+obj-$(CONFIG_MAC80211) += mac80211.o - - mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o - mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o - mac80211-objs-$(CONFIG_NET_SCHED) += wme.o -+mac80211-objs-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o - - mac80211-objs := \ - ieee80211.o \ -Index: mac80211/net/mac80211/rc80211_simple.c -=================================================================== ---- mac80211.orig/net/mac80211/rc80211_simple.c 2007-11-11 15:45:23.237494839 +0100 -+++ mac80211/net/mac80211/rc80211_simple.c 2007-11-11 15:45:30.449905846 +0100 -@@ -7,7 +7,6 @@ - * published by the Free Software Foundation. - */ - --#include <linux/module.h> - #include <linux/init.h> - #include <linux/netdevice.h> - #include <linux/types.h> -@@ -29,8 +28,6 @@ - #define RATE_CONTROL_INTERVAL (HZ / 20) - #define RATE_CONTROL_MIN_TX 10 - --MODULE_ALIAS("rc80211_default"); -- - static void rate_control_rate_inc(struct ieee80211_local *local, - struct sta_info *sta) - { -@@ -393,8 +390,7 @@ - } - #endif - --static struct rate_control_ops rate_control_simple = { -- .module = THIS_MODULE, -+struct rate_control_ops mac80211_rcsimple = { - .name = "simple", - .tx_status = rate_control_simple_tx_status, - .get_rate = rate_control_simple_get_rate, -@@ -409,22 +405,3 @@ - .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs, - #endif - }; -- -- --static int __init rate_control_simple_init(void) --{ -- return ieee80211_rate_control_register(&rate_control_simple); --} -- -- --static void __exit rate_control_simple_exit(void) --{ -- ieee80211_rate_control_unregister(&rate_control_simple); --} -- -- --subsys_initcall(rate_control_simple_init); --module_exit(rate_control_simple_exit); -- --MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211"); --MODULE_LICENSE("GPL"); -Index: mac80211/net/mac80211/rx.c -=================================================================== ---- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:45:23.245495291 +0100 -+++ mac80211/net/mac80211/rx.c 2007-11-11 15:45:30.449905846 +0100 -@@ -509,9 +509,11 @@ - rx->key->tx_rx_count++; - /* TODO: add threshold stuff again */ - } else { -+#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX protected frame," - " but have no key\n", rx->dev->name); -+#endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; - } - -Index: mac80211/net/mac80211/wep.c -=================================================================== ---- mac80211.orig/net/mac80211/wep.c 2007-11-11 15:45:23.253495749 +0100 -+++ mac80211/net/mac80211/wep.c 2007-11-11 15:45:30.449905846 +0100 -@@ -16,7 +16,7 @@ - #include <linux/crypto.h> - #include <linux/err.h> - #include <linux/mm.h> --#include <asm/scatterlist.h> -+#include <linux/scatterlist.h> - - #include <net/mac80211.h> - #include "ieee80211_i.h" -@@ -138,9 +138,7 @@ - *icv = cpu_to_le32(~crc32_le(~0, data, data_len)); - - crypto_blkcipher_setkey(tfm, rc4key, klen); -- sg.page = virt_to_page(data); -- sg.offset = offset_in_page(data); -- sg.length = data_len + WEP_ICV_LEN; -+ sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); - } - -@@ -204,9 +202,7 @@ - __le32 crc; - - crypto_blkcipher_setkey(tfm, rc4key, klen); -- sg.page = virt_to_page(data); -- sg.offset = offset_in_page(data); -- sg.length = data_len + WEP_ICV_LEN; -+ sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); - - crc = cpu_to_le32(~crc32_le(~0, data, data_len)); -@@ -318,9 +314,11 @@ - - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { - if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { -+#ifdef CONFIG_MAC80211_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); -+#endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; - } - } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { -Index: mac80211/net/wireless/Kconfig -=================================================================== ---- mac80211.orig/net/wireless/Kconfig 2007-11-11 15:45:23.261496205 +0100 -+++ mac80211/net/wireless/Kconfig 2007-11-11 15:45:30.453906075 +0100 -@@ -3,7 +3,7 @@ - - config NL80211 - bool "nl80211 new netlink interface support" -- depends CFG80211 -+ depends on CFG80211 - default y - ---help--- - This option turns on the new netlink interface diff --git a/package/mac80211/patches/001-port-to-2.6.23.patch b/package/mac80211/patches/001-port-to-2.6.23.patch new file mode 100644 index 0000000000..2e88d405e3 --- /dev/null +++ b/package/mac80211/patches/001-port-to-2.6.23.patch @@ -0,0 +1,231 @@ +Index: mac80211/net/mac80211/ieee80211.c +=================================================================== +--- mac80211.orig/net/mac80211/ieee80211.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/ieee80211.c 2008-02-15 22:21:01.000000000 +0100 +@@ -21,7 +21,6 @@ + #include <linux/wireless.h> + #include <linux/rtnetlink.h> + #include <linux/bitmap.h> +-#include <net/net_namespace.h> + #include <net/cfg80211.h> + + #include "ieee80211_i.h" +@@ -36,6 +35,15 @@ + + #define SUPP_MCS_SET_LEN 16 + ++ ++char *print_mac(char *buf, const u8 *addr) ++{ ++ sprintf(buf, MAC_FMT, ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ return buf; ++} ++ ++ + /* + * For seeing transmitted packets on monitor interfaces + * we have a radiotap header too. +@@ -48,11 +56,13 @@ struct ieee80211_tx_status_rtap_hdr { + + /* common interface routines */ + ++#if 0 + static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) + { + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ + return ETH_ALEN; + } ++#endif + + /* must be called under mdev tx lock */ + static void ieee80211_configure_filter(struct ieee80211_local *local) +@@ -800,6 +810,7 @@ static void ieee80211_set_multicast_list + dev_mc_sync(local->mdev, dev); + } + ++#if 0 + static const struct header_ops ieee80211_header_ops = { + .create = eth_header, + .parse = header_parse_80211, +@@ -807,6 +818,7 @@ static const struct header_ops ieee80211 + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, + }; ++#endif + + /* Must not be called for mdev */ + void ieee80211_if_setup(struct net_device *dev) +@@ -1455,7 +1467,7 @@ struct ieee80211_hw *ieee80211_alloc_hw( + mdev->open = ieee80211_master_open; + mdev->stop = ieee80211_master_stop; + mdev->type = ARPHRD_IEEE80211; +- mdev->header_ops = &ieee80211_header_ops; ++// mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; + + sdata->vif.type = IEEE80211_IF_TYPE_AP; +Index: mac80211/net/mac80211/ieee80211_i.h +=================================================================== +--- mac80211.orig/net/mac80211/ieee80211_i.h 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/ieee80211_i.h 2008-02-15 22:21:37.000000000 +0100 +@@ -26,6 +26,16 @@ + #include "ieee80211_key.h" + #include "sta_info.h" + ++ ++#define BIT(nr) (1 << (nr)) ++ ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++extern char *print_mac(char *buf, const u8 *addr); ++#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused ++ ++#define CONFIG_MAC80211_RC_DEFAULT __stringify(__CONFIG_MAC80211_RC_DEFAULT) ++ ++ + /* ieee80211.o internal definitions, etc. These are not included into + * low-level drivers. */ + +Index: mac80211/net/mac80211/ieee80211_ioctl.c +=================================================================== +--- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/ieee80211_ioctl.c 2008-02-15 22:21:01.000000000 +0100 +@@ -207,7 +207,7 @@ static int ieee80211_ioctl_giwrange(stru + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + +- range->scan_capa |= IW_SCAN_CAPA_ESSID; ++// range->scan_capa |= IW_SCAN_CAPA_ESSID; + + return 0; + } +Index: mac80211/net/wireless/core.c +=================================================================== +--- mac80211.orig/net/wireless/core.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/wireless/core.c 2008-02-15 22:21:01.000000000 +0100 +@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_inf + + if (info->attrs[NL80211_ATTR_IFINDEX]) { + ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(ifindex); + if (dev) { + if (dev->ieee80211_ptr) + byifidx = +@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifinde + struct net_device *dev; + + mutex_lock(&cfg80211_drv_mutex); +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(ifindex); + if (!dev) + goto out; + if (dev->ieee80211_ptr) { +Index: mac80211/net/wireless/nl80211.c +=================================================================== +--- mac80211.orig/net/wireless/nl80211.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/wireless/nl80211.c 2008-02-15 22:21:01.000000000 +0100 +@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(s + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); +- *dev = dev_get_by_index(&init_net, ifindex); ++ *dev = dev_get_by_index(ifindex); + if (!*dev) + return -ENODEV; + +@@ -959,7 +959,7 @@ static int get_vlan(struct nlattr *vlana + *vlan = NULL; + + if (vlanattr) { +- *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); ++ *vlan = dev_get_by_index(nla_get_u32(vlanattr)); + if (!*vlan) + return -ENODEV; + if (!(*vlan)->ieee80211_ptr) +Index: mac80211/net/mac80211/cfg.c +=================================================================== +--- mac80211.orig/net/mac80211/cfg.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/cfg.c 2008-02-15 22:21:01.000000000 +0100 +@@ -9,7 +9,6 @@ + #include <linux/ieee80211.h> + #include <linux/nl80211.h> + #include <linux/rtnetlink.h> +-#include <net/net_namespace.h> + #include <linux/rcupdate.h> + #include <net/cfg80211.h> + #include "ieee80211_i.h" +@@ -68,7 +67,7 @@ static int ieee80211_del_iface(struct wi + return -ENODEV; + + /* we're under RTNL */ +- dev = __dev_get_by_index(&init_net, ifindex); ++ dev = __dev_get_by_index(ifindex); + if (!dev) + return 0; + +@@ -89,7 +88,7 @@ static int ieee80211_change_iface(struct + return -ENODEV; + + /* we're under RTNL */ +- dev = __dev_get_by_index(&init_net, ifindex); ++ dev = __dev_get_by_index(ifindex); + if (!dev) + return -ENODEV; + +Index: mac80211/net/mac80211/tx.c +=================================================================== +--- mac80211.orig/net/mac80211/tx.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/tx.c 2008-02-15 22:21:01.000000000 +0100 +@@ -18,7 +18,6 @@ + #include <linux/etherdevice.h> + #include <linux/bitmap.h> + #include <linux/rcupdate.h> +-#include <net/net_namespace.h> + #include <net/ieee80211_radiotap.h> + #include <net/cfg80211.h> + #include <net/mac80211.h> +@@ -1051,7 +1050,7 @@ static int ieee80211_tx_prepare(struct i + struct net_device *dev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; +- dev = dev_get_by_index(&init_net, pkt_data->ifindex); ++ dev = dev_get_by_index(pkt_data->ifindex); + if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { + dev_put(dev); + dev = NULL; +@@ -1265,7 +1264,7 @@ int ieee80211_master_start_xmit(struct s + memset(&control, 0, sizeof(struct ieee80211_tx_control)); + + if (pkt_data->ifindex) +- odev = dev_get_by_index(&init_net, pkt_data->ifindex); ++ odev = dev_get_by_index(pkt_data->ifindex); + if (unlikely(odev && !is_ieee80211_device(odev, dev))) { + dev_put(odev); + odev = NULL; +Index: mac80211/net/mac80211/util.c +=================================================================== +--- mac80211.orig/net/mac80211/util.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/mac80211/util.c 2008-02-15 22:21:01.000000000 +0100 +@@ -20,7 +20,6 @@ + #include <linux/if_arp.h> + #include <linux/wireless.h> + #include <linux/bitmap.h> +-#include <net/net_namespace.h> + #include <net/cfg80211.h> + #include <net/rtnetlink.h> + +Index: mac80211/net/wireless/sysfs.c +=================================================================== +--- mac80211.orig/net/wireless/sysfs.c 2008-02-15 22:20:53.000000000 +0100 ++++ mac80211/net/wireless/sysfs.c 2008-02-15 22:21:01.000000000 +0100 +@@ -53,7 +53,8 @@ static void wiphy_dev_release(struct dev + } + + #ifdef CONFIG_HOTPLUG +-static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) ++static int wiphy_uevent(struct device *dev, char **envp, int num_envp, ++ char *buffer, int buffer_size) + { + /* TODO, we probably need stuff here */ + return 0; diff --git a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch b/package/mac80211/patches/008-add-hostapd-ioctl-header.patch deleted file mode 100644 index acea0ce969..0000000000 --- a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch +++ /dev/null @@ -1,110 +0,0 @@ ---- - net/mac80211/hostapd_ioctl.h | 103 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 103 insertions(+) - ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ everything/net/mac80211/hostapd_ioctl.h 2007-11-07 13:19:23.031516330 +0100 -@@ -0,0 +1,103 @@ -+/* -+ * Host AP (software wireless LAN access point) user space daemon for -+ * Host AP kernel driver -+ * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> -+ * Copyright 2002-2004, Instant802 Networks, Inc. -+ * Copyright 2005, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef HOSTAPD_IOCTL_H -+#define HOSTAPD_IOCTL_H -+ -+#ifdef __KERNEL__ -+#include <linux/types.h> -+#endif /* __KERNEL__ */ -+ -+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -+#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3) -+ -+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: -+ * This table is no longer added to, the whole sub-ioctl -+ * mess shall be deleted completely. */ -+enum { -+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, -+ PRISM2_PARAM_IEEE_802_1X = 23, -+ -+ /* Instant802 additions */ -+ PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001, -+ PRISM2_PARAM_PREAMBLE = 1003, -+ PRISM2_PARAM_SHORT_SLOT_TIME = 1006, -+ PRISM2_PARAM_NEXT_MODE = 1008, -+ PRISM2_PARAM_PRIVACY_INVOKED = 1014, -+ PRISM2_PARAM_EAPOL = 1023, -+ PRISM2_PARAM_MGMT_IF = 1046, -+}; -+ -+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: -+ * This table is no longer added to, the hostapd ioctl -+ * shall be deleted completely. */ -+enum { -+ PRISM2_HOSTAPD_FLUSH = 1, -+ -+ /* Instant802 additions */ -+ PRISM2_HOSTAPD_GET_HW_FEATURES = 1002, -+ PRISM2_HOSTAPD_SET_RATE_SETS = 1005, -+ PRISM2_HOSTAPD_SET_CHANNEL_FLAG = 1012, -+ PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN = 1013, -+ PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS = 1014, -+}; -+ -+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048 -+#define ALIGNED __attribute__ ((aligned)) -+ -+struct prism2_hostapd_param { -+ u32 cmd; -+ u8 sta_addr[ETH_ALEN]; -+ u8 pad[2]; -+ union { -+ struct { -+ u16 num_modes; -+ u16 flags; -+ u8 data[0] ALIGNED; /* num_modes * feature data */ -+ } hw_features; -+ struct { -+ u16 mode; /* MODE_* */ -+ u16 num_supported_rates; -+ u16 num_basic_rates; -+ u8 data[0] ALIGNED; /* num_supported_rates * u16 + -+ * num_basic_rates * u16 */ -+ } set_rate_sets; -+ struct { -+ u16 mode; /* MODE_* */ -+ u16 chan; -+ u32 flag; -+ u8 power_level; /* regulatory limit in dBm */ -+ u8 antenna_max; -+ } set_channel_flag; -+ struct { -+ u32 rd; -+ } set_regulatory_domain; -+ struct { -+ u32 queue; -+ s32 aifs; -+ u32 cw_min; -+ u32 cw_max; -+ u32 burst_time; /* maximum burst time in 0.1 ms, i.e., -+ * 10 = 1 ms */ -+ } tx_queue_params; -+ } u; -+}; -+ -+/* Data structures used for get_hw_features ioctl */ -+struct hostapd_ioctl_hw_modes_hdr { -+ int mode; -+ int num_channels; -+ int num_rates; -+}; -+ -+#endif /* HOSTAPD_IOCTL_H */ diff --git a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch b/package/mac80211/patches/009-add-old-ioctl-skeleton.patch deleted file mode 100644 index fb9f25f62a..0000000000 --- a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch +++ /dev/null @@ -1,187 +0,0 @@ ---- - net/mac80211/ieee80211.c | 5 + - net/mac80211/ieee80211_ioctl.c | 121 +++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 126 insertions(+) - ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:06:34.902124618 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:24.311521482 +0100 -@@ -21,6 +21,7 @@ - - #include <net/mac80211.h> - #include "ieee80211_i.h" -+#include "hostapd_ioctl.h" - #include "ieee80211_rate.h" - #include "wpa.h" - #include "aes_ccm.h" -@@ -124,6 +125,47 @@ static int ieee80211_ioctl_siwgenie(stru - return -EOPNOTSUPP; - } - -+ -+static int ieee80211_ioctl_priv_hostapd(struct net_device *dev, -+ struct iw_point *p) -+{ -+ struct prism2_hostapd_param *param; -+ int ret = 0; -+ -+ if (p->length < sizeof(struct prism2_hostapd_param) || -+ p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) { -+ printk(KERN_DEBUG "%s: hostapd ioctl: ptr=%p len=%d min=%d " -+ "max=%d\n", dev->name, p->pointer, p->length, -+ (int)sizeof(struct prism2_hostapd_param), -+ PRISM2_HOSTAPD_MAX_BUF_SIZE); -+ return -EINVAL; -+ } -+ -+ param = kmalloc(p->length, GFP_KERNEL); -+ if (!param) -+ return -ENOMEM; -+ -+ if (copy_from_user(param, p->pointer, p->length)) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ switch (param->cmd) { -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ if (copy_to_user(p->pointer, param, p->length)) -+ ret = -EFAULT; -+ -+ out: -+ kfree(param); -+ -+ return ret; -+} -+ -+ - static int ieee80211_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -@@ -819,6 +861,49 @@ static int ieee80211_ioctl_giwretry(stru - return 0; - } - -+static int ieee80211_ioctl_prism2_param(struct net_device *dev, -+ struct iw_request_info *info, -+ void *wrqu, char *extra) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ int *i = (int *) extra; -+ int param = *i; -+ int ret = 0; -+ -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ -+ switch (param) { -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ return ret; -+} -+ -+ -+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, -+ struct iw_request_info *info, -+ void *wrqu, char *extra) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ int *param = (int *) extra; -+ int ret = 0; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ -+ switch (*param) { -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ return ret; -+} -+ - static int ieee80211_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -@@ -1073,6 +1158,32 @@ static int ieee80211_ioctl_siwencodeext( - } - - -+static const struct iw_priv_args ieee80211_ioctl_priv[] = { -+ { PRISM2_IOCTL_PRISM2_PARAM, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" }, -+ { PRISM2_IOCTL_GET_PRISM2_PARAM, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" }, -+}; -+ -+ -+int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ struct iwreq *wrq = (struct iwreq *) rq; -+ -+ switch (cmd) { -+ /* Private ioctls (iwpriv) that have not yet been converted -+ * into new wireless extensions API */ -+ case PRISM2_IOCTL_HOSTAPD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ return ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data); -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+ - /* Structures to export the Wireless Handlers */ - - static const iw_handler ieee80211_handler[] = -@@ -1135,9 +1246,19 @@ static const iw_handler ieee80211_handle - (iw_handler) NULL, /* -- hole -- */ - }; - -+static const iw_handler ieee80211_private_handler[] = -+{ /* SIOCIWFIRSTPRIV + */ -+ (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */ -+ (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */ -+}; -+ - const struct iw_handler_def ieee80211_iw_handler_def = - { - .num_standard = ARRAY_SIZE(ieee80211_handler), -+ .num_private = ARRAY_SIZE(ieee80211_private_handler), -+ .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv), - .standard = (iw_handler *) ieee80211_handler, -+ .private = (iw_handler *) ieee80211_private_handler, -+ .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv, - .get_wireless_stats = ieee80211_get_wireless_stats, - }; ---- everything.orig/net/mac80211/ieee80211.c 2007-11-07 13:18:36.001511500 +0100 -+++ everything/net/mac80211/ieee80211.c 2007-11-07 13:19:24.311521482 +0100 -@@ -413,6 +413,9 @@ static const struct header_ops ieee80211 - .cache_update = eth_header_cache_update, - }; - -+/* HACK */ -+extern int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -+ - /* Must not be called for mdev */ - void ieee80211_if_setup(struct net_device *dev) - { -@@ -425,6 +428,8 @@ void ieee80211_if_setup(struct net_devic - dev->open = ieee80211_open; - dev->stop = ieee80211_stop; - dev->destructor = ieee80211_if_free; -+ -+ dev->do_ioctl = ieee80211_ioctl; - } - - /* WDS specialties */ diff --git a/package/mac80211/patches/010-add-mgmt-iface.patch b/package/mac80211/patches/010-add-mgmt-iface.patch deleted file mode 100644 index eae5ff6d5e..0000000000 --- a/package/mac80211/patches/010-add-mgmt-iface.patch +++ /dev/null @@ -1,688 +0,0 @@ ---- - include/net/mac80211.h | 1 - net/mac80211/ieee80211.c | 198 ++++++++++++++++++++++++++++++++++++++-- - net/mac80211/ieee80211_common.h | 64 ++++++++++++ - net/mac80211/ieee80211_i.h | 9 + - net/mac80211/ieee80211_iface.c | 66 +++++++++++++ - net/mac80211/ieee80211_ioctl.c | 21 ++++ - net/mac80211/ieee80211_rate.c | 3 - net/mac80211/ieee80211_rate.h | 2 - net/mac80211/ieee80211_sta.c | 2 - net/mac80211/rx.c | 29 ++++- - net/mac80211/tx.c | 14 ++ - net/mac80211/wme.c | 10 +- - 12 files changed, 399 insertions(+), 20 deletions(-) - -Index: mac80211/include/net/mac80211.h -=================================================================== ---- mac80211.orig/include/net/mac80211.h 2007-11-11 15:15:42.824034853 +0100 -+++ mac80211/include/net/mac80211.h 2007-11-11 15:15:53.784659457 +0100 -@@ -472,6 +472,7 @@ - enum ieee80211_if_types { - IEEE80211_IF_TYPE_INVALID, - IEEE80211_IF_TYPE_AP, -+ IEEE80211_IF_TYPE_MGMT, - IEEE80211_IF_TYPE_STA, - IEEE80211_IF_TYPE_IBSS, - IEEE80211_IF_TYPE_MNTR, -Index: mac80211/net/mac80211/ieee80211.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:15:51.536531354 +0100 -+++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:16:22.214279577 +0100 -@@ -23,6 +23,7 @@ - #include <linux/bitmap.h> - #include <net/cfg80211.h> - -+#include "ieee80211_common.h" - #include "ieee80211_i.h" - #include "ieee80211_rate.h" - #include "wep.h" -@@ -121,6 +122,152 @@ - ieee80211_configure_filter(local); - } - -+/* management interface */ -+ -+static void -+ieee80211_fill_frame_info(struct ieee80211_local *local, -+ struct ieee80211_frame_info *fi, -+ struct ieee80211_rx_status *status) -+{ -+ if (status) { -+ struct timespec ts; -+ struct ieee80211_rate *rate; -+ -+ jiffies_to_timespec(jiffies, &ts); -+ fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + -+ ts.tv_nsec / 1000); -+ fi->mactime = cpu_to_be64(status->mactime); -+ switch (status->phymode) { -+ case MODE_IEEE80211A: -+ fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); -+ break; -+ case MODE_IEEE80211B: -+ fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); -+ break; -+ case MODE_IEEE80211G: -+ fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); -+ break; -+ default: -+ fi->phytype = htonl(0xAAAAAAAA); -+ break; -+ } -+ fi->channel = htonl(status->channel); -+ rate = ieee80211_get_rate(local, status->phymode, -+ status->rate); -+ if (rate) { -+ fi->datarate = htonl(rate->rate); -+ if (rate->flags & IEEE80211_RATE_PREAMBLE2) { -+ if (status->rate == rate->val) -+ fi->preamble = htonl(2); /* long */ -+ else if (status->rate == rate->val2) -+ fi->preamble = htonl(1); /* short */ -+ } else -+ fi->preamble = htonl(0); -+ } else { -+ fi->datarate = htonl(0); -+ fi->preamble = htonl(0); -+ } -+ -+ fi->antenna = htonl(status->antenna); -+ fi->priority = htonl(0xffffffff); /* no clue */ -+ fi->ssi_type = htonl(ieee80211_ssi_raw); -+ fi->ssi_signal = htonl(status->ssi); -+ fi->ssi_noise = 0x00000000; -+ fi->encoding = 0; -+ } else { -+ /* clear everything because we really don't know. -+ * the msg_type field isn't present on monitor frames -+ * so we don't know whether it will be present or not, -+ * but it's ok to not clear it since it'll be assigned -+ * anyway */ -+ memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); -+ -+ fi->ssi_type = htonl(ieee80211_ssi_none); -+ } -+ fi->version = htonl(IEEE80211_FI_VERSION); -+ fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); -+} -+ -+/* this routine is actually not just for this, but also -+ * for pushing fake 'management' frames into userspace. -+ * it shall be replaced by a netlink-based system. */ -+void -+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, -+ struct ieee80211_rx_status *status, u32 msg_type) -+{ -+ struct ieee80211_frame_info *fi; -+ const size_t hlen = sizeof(struct ieee80211_frame_info); -+ struct net_device *dev = local->apdev; -+ -+ skb->dev = dev; -+ -+ if (skb_headroom(skb) < hlen) { -+ I802_DEBUG_INC(local->rx_expand_skb_head); -+ if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { -+ dev_kfree_skb(skb); -+ return; -+ } -+ } -+ -+ fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); -+ -+ ieee80211_fill_frame_info(local, fi, status); -+ fi->msg_type = htonl(msg_type); -+ -+ dev->stats.rx_packets++; -+ dev->stats.rx_bytes += skb->len; -+ -+ skb_set_mac_header(skb, 0); -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ skb->pkt_type = PACKET_OTHERHOST; -+ skb->protocol = htons(ETH_P_802_2); -+ memset(skb->cb, 0, sizeof(skb->cb)); -+ netif_rx(skb); -+} -+ -+static int ieee80211_mgmt_open(struct net_device *dev) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ -+ if (!netif_running(local->mdev)) -+ return -EOPNOTSUPP; -+ return 0; -+} -+ -+static int ieee80211_mgmt_stop(struct net_device *dev) -+{ -+ return 0; -+} -+ -+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) -+{ -+ /* FIX: what would be proper limits for MTU? -+ * This interface uses 802.11 frames. */ -+ if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { -+ printk(KERN_WARNING "%s: invalid MTU %d\n", -+ dev->name, new_mtu); -+ return -EINVAL; -+ } -+ -+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG -+ printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ -+ dev->mtu = new_mtu; -+ return 0; -+} -+ -+void ieee80211_if_mgmt_setup(struct net_device *dev) -+{ -+ ether_setup(dev); -+ dev->hard_start_xmit = ieee80211_mgmt_start_xmit; -+ dev->change_mtu = ieee80211_change_mtu_apdev; -+ dev->open = ieee80211_mgmt_open; -+ dev->stop = ieee80211_mgmt_stop; -+ dev->type = ARPHRD_IEEE80211_PRISM; -+ dev->hard_header_parse = &header_parse_80211; -+ dev->destructor = ieee80211_if_free; -+} -+ - /* regular interfaces */ - - static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) -@@ -198,6 +345,7 @@ - return -ENOLINK; - break; - case IEEE80211_IF_TYPE_AP: -+ case IEEE80211_IF_TYPE_MGMT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_IBSS: -@@ -262,6 +410,10 @@ - if (local->open_count == 0) { - res = dev_open(local->mdev); - WARN_ON(res); -+ if (local->apdev) { -+ res = dev_open(local->apdev); -+ WARN_ON(res); -+ } - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - } -@@ -347,6 +499,9 @@ - if (netif_running(local->mdev)) - dev_close(local->mdev); - -+ if (local->apdev) -+ dev_close(local->apdev); -+ - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - -@@ -646,6 +801,8 @@ - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - if (control->flags & IEEE80211_TXCTL_REQUEUE) - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; -+ if (control->type == IEEE80211_IF_TYPE_MGMT) -+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; - pkt_data->queue = control->queue; - - hdrlen = ieee80211_get_hdrlen_from_skb(skb); -@@ -698,6 +855,7 @@ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_local *local = hw_to_local(hw); - u16 frag, type; -+ u32 msg_type; - struct ieee80211_tx_status_rtap_hdr *rthdr; - struct ieee80211_sub_if_data *sdata; - int monitors; -@@ -812,9 +970,29 @@ - local->dot11FailedCount++; - } - -+ msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? -+ ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; -+ - /* this was a transmitted frame, but now we want to reuse it */ - skb_orphan(skb); - -+ if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) && -+ local->apdev) { -+ if (local->monitors) { -+ skb2 = skb_clone(skb, GFP_ATOMIC); -+ } else { -+ skb2 = skb; -+ skb = NULL; -+ } -+ -+ if (skb2) -+ /* Send frame to hostapd */ -+ ieee80211_rx_mgmt(local, skb2, NULL, msg_type); -+ -+ if (!skb) -+ return; -+ } -+ - if (!local->monitors) { - dev_kfree_skb(skb); - return; -@@ -1161,6 +1339,8 @@ - BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); - - local->reg_state = IEEE80211_DEV_UNREGISTERED; -+ if (local->apdev) -+ ieee80211_if_del_mgmt(local); - - /* - * At this point, interface list manipulations are fine -Index: mac80211/net/mac80211/ieee80211_i.h -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:42.840035769 +0100 -+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100 -@@ -142,6 +142,7 @@ - * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; - int last_frag_hwrate; -+ int mgmt_interface; - - /* Extra fragments (in addition to the first fragment - * in skb) */ -@@ -163,6 +164,7 @@ - #define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) - #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) - #define IEEE80211_TXPD_REQUEUE BIT(2) -+#define IEEE80211_TXPD_MGMT_IFACE BIT(3) - /* Stored in sk_buff->cb */ - struct ieee80211_tx_packet_data { - int ifindex; -@@ -408,6 +410,7 @@ - struct list_head modes_list; - - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ -+ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ - int open_count; - int monitors; - unsigned int filter_flags; /* FIF_* */ -@@ -701,11 +704,14 @@ - int ieee80211_hw_config(struct ieee80211_local *local); - int ieee80211_if_config(struct net_device *dev); - int ieee80211_if_config_beacon(struct net_device *dev); -+void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, -+ struct ieee80211_rx_status *status, u32 msg_type); - void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode); - void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); - int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); - void ieee80211_if_setup(struct net_device *dev); -+void ieee80211_if_mgmt_setup(struct net_device *dev); - struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, - int phymode, int hwrate); - -@@ -772,6 +778,8 @@ - int ieee80211_if_remove(struct net_device *dev, const char *name, int id); - void ieee80211_if_free(struct net_device *dev); - void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -+int ieee80211_if_add_mgmt(struct ieee80211_local *local); -+void ieee80211_if_del_mgmt(struct ieee80211_local *local); - - /* regdomain.c */ - void ieee80211_regdomain_init(void); -@@ -788,6 +796,7 @@ - int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); - int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); - int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); -+int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); - - /* utility functions/constants */ - extern void *mac80211_wiphy_privid; /* for wiphy privid */ -Index: mac80211/net/mac80211/ieee80211_iface.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:42.848036222 +0100 -+++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100 -@@ -96,6 +96,66 @@ - return ret; - } - -+int ieee80211_if_add_mgmt(struct ieee80211_local *local) -+{ -+ struct net_device *ndev; -+ struct ieee80211_sub_if_data *nsdata; -+ int ret; -+ -+ ASSERT_RTNL(); -+ -+ ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d", -+ ieee80211_if_mgmt_setup); -+ if (!ndev) -+ return -ENOMEM; -+ ret = dev_alloc_name(ndev, ndev->name); -+ if (ret < 0) -+ goto fail; -+ -+ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); -+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); -+ -+ nsdata = IEEE80211_DEV_TO_SUB_IF(ndev); -+ ndev->ieee80211_ptr = &nsdata->wdev; -+ nsdata->wdev.wiphy = local->hw.wiphy; -+ nsdata->type = IEEE80211_IF_TYPE_MGMT; -+ nsdata->dev = ndev; -+ nsdata->local = local; -+ ieee80211_if_sdata_init(nsdata); -+ -+ ret = register_netdevice(ndev); -+ if (ret) -+ goto fail; -+ -+ /* -+ * Called even when register_netdevice fails, it would -+ * oops if assigned before initialising the rest. -+ */ -+ ndev->uninit = ieee80211_if_reinit; -+ -+ ieee80211_debugfs_add_netdev(nsdata); -+ -+ if (local->open_count > 0) -+ dev_open(ndev); -+ local->apdev = ndev; -+ return 0; -+ -+fail: -+ free_netdev(ndev); -+ return ret; -+} -+ -+void ieee80211_if_del_mgmt(struct ieee80211_local *local) -+{ -+ struct net_device *apdev; -+ -+ ASSERT_RTNL(); -+ apdev = local->apdev; -+ ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); -+ local->apdev = NULL; -+ unregister_netdevice(apdev); -+} -+ - void ieee80211_if_set_type(struct net_device *dev, int type) - { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -@@ -183,6 +243,9 @@ - ieee80211_if_sdata_deinit(sdata); - - switch (sdata->type) { -+ case IEEE80211_IF_TYPE_MGMT: -+ /* nothing to do */ -+ break; - case IEEE80211_IF_TYPE_INVALID: - /* cannot happen */ - WARN_ON(1); -@@ -294,8 +357,11 @@ - - void ieee80211_if_free(struct net_device *dev) - { -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - -+ /* local->apdev must be NULL when freeing management interface */ -+ BUG_ON(dev == local->apdev); - ieee80211_if_sdata_deinit(sdata); - free_netdev(dev); - } -Index: mac80211/net/mac80211/ieee80211_rate.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:42.852036451 +0100 -+++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:53.800660386 +0100 -@@ -145,7 +145,8 @@ - struct rate_control_ref *ref, *old; - - ASSERT_RTNL(); -- if (local->open_count || netif_running(local->mdev)) -+ if (local->open_count || netif_running(local->mdev) || -+ (local->apdev && netif_running(local->apdev))) - return -EBUSY; - - ref = rate_control_alloc(name, local); -Index: mac80211/net/mac80211/ieee80211_rate.h -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:42.860036908 +0100 -+++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:53.800660386 +0100 -@@ -30,6 +30,8 @@ - - /* parameters from the caller to rate_control_get_rate(): */ - struct ieee80211_hw_mode *mode; -+ int mgmt_data; /* this is data frame that is used for management -+ * (e.g., IEEE 802.1X EAPOL) */ - u16 ethertype; - }; - -Index: mac80211/net/mac80211/ieee80211_sta.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:42.868037362 +0100 -+++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:53.800660386 +0100 -@@ -475,6 +475,8 @@ - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; -+ if (sdata->type == IEEE80211_IF_TYPE_MGMT) -+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; - if (!encrypt) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - -Index: mac80211/net/mac80211/rx.c -=================================================================== ---- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:15:42.872037591 +0100 -+++ mac80211/net/mac80211/rx.c 2007-11-11 15:15:53.804660611 +0100 -@@ -19,6 +19,7 @@ - - #include "ieee80211_i.h" - #include "ieee80211_led.h" -+#include "ieee80211_common.h" - #include "wep.h" - #include "wpa.h" - #include "tkip.h" -@@ -411,7 +412,12 @@ - return TXRX_DROP; - } - -- return TXRX_DROP; -+ if (!rx->local->apdev) -+ return TXRX_DROP; -+ -+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, -+ ieee80211_msg_sta_not_assoc); -+ return TXRX_QUEUED; - } - - return TXRX_CONTINUE; -@@ -953,8 +959,15 @@ - { - if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA && -- (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) -- return TXRX_CONTINUE; -+ (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { -+ /* Pass both encrypted and unencrypted EAPOL frames to user -+ * space for processing. */ -+ if (!rx->local->apdev) -+ return TXRX_DROP; -+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, -+ ieee80211_msg_normal); -+ return TXRX_QUEUED; -+ } - - if (unlikely(rx->sdata->ieee802_1x && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && -@@ -1196,8 +1209,13 @@ - sdata->type == IEEE80211_IF_TYPE_IBSS) && - !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) - ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); -- else -- return TXRX_DROP; -+ else { -+ /* Management frames are sent to hostapd for processing */ -+ if (!rx->local->apdev) -+ return TXRX_DROP; -+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, -+ ieee80211_msg_normal); -+ } - - return TXRX_QUEUED; - } -@@ -1407,6 +1425,7 @@ - /* take everything */ - break; - case IEEE80211_IF_TYPE_INVALID: -+ case IEEE80211_IF_TYPE_MGMT: - /* should never get here */ - WARN_ON(1); - break; -Index: mac80211/net/mac80211/tx.c -=================================================================== ---- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:42.880038048 +0100 -+++ mac80211/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100 -@@ -258,7 +258,7 @@ - return TXRX_CONTINUE; - } - -- if (unlikely(/* !injected && */ tx->sdata->ieee802_1x && -+ if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && - !(sta_flags & WLAN_STA_AUTHORIZED))) { - #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT -@@ -568,6 +568,8 @@ - memset(&extra, 0, sizeof(extra)); - extra.mode = tx->u.tx.mode; - extra.ethertype = tx->ethertype; -+ extra.mgmt_data = tx->sdata && -+ tx->sdata->type == IEEE80211_IF_TYPE_MGMT; - - tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, - tx->skb, &extra); -@@ -1076,7 +1078,7 @@ - } - - static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, -- struct ieee80211_tx_control *control) -+ struct ieee80211_tx_control *control, int mgmt) - { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; -@@ -1107,6 +1109,7 @@ - rcu_read_lock(); - - sta = tx.sta; -+ tx.u.tx.mgmt_interface = mgmt; - tx.u.tx.mode = local->hw.conf.mode; - - for (handler = local->tx_handlers; *handler != NULL; -@@ -1253,7 +1256,8 @@ - control.flags |= IEEE80211_TXCTL_REQUEUE; - control.queue = pkt_data->queue; - -- ret = ieee80211_tx(odev, skb, &control); -+ ret = ieee80211_tx(odev, skb, &control, -+ control.type == IEEE80211_IF_TYPE_MGMT); - dev_put(odev); - - return ret; -@@ -1498,6 +1502,8 @@ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; -+ if (sdata->type == IEEE80211_IF_TYPE_MGMT) -+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; - - skb->dev = local->mdev; - dev->stats.tx_packets++; -@@ -1555,6 +1561,8 @@ - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; -+ if (sdata->type == IEEE80211_IF_TYPE_MGMT) -+ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; - - skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ - skb->dev = sdata->local->mdev; -Index: mac80211/net/mac80211/wme.c -=================================================================== ---- mac80211.orig/net/mac80211/wme.c 2007-11-11 15:15:42.888038502 +0100 -+++ mac80211/net/mac80211/wme.c 2007-11-11 15:15:53.804660611 +0100 -@@ -94,6 +94,8 @@ - static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) - { - struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); -+ struct ieee80211_tx_packet_data *pkt_data = -+ (struct ieee80211_tx_packet_data *) skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - unsigned short fc = le16_to_cpu(hdr->frame_control); - int qos; -@@ -106,8 +108,12 @@ - return IEEE80211_TX_QUEUE_DATA0; - } - -- if (0 /* injected */) { -- /* use AC from radiotap */ -+ if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) { -+ /* Data frames from hostapd (mainly, EAPOL) use AC_VO -+ * and they will include QoS control fields if -+ * the target STA is using WME. */ -+ skb->priority = 7; -+ return ieee802_1d_to_ac[skb->priority]; - } - - /* is this a QoS frame? */ -Index: mac80211/net/mac80211/ieee80211_ioctl.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:51.532531127 +0100 -+++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:53.808660833 +0100 -@@ -840,16 +840,29 @@ - void *wrqu, char *extra) - { - struct ieee80211_sub_if_data *sdata; -+ struct ieee80211_local *local; - int *i = (int *) extra; - int param = *i; -+ int value = *(i + 1); - int ret = 0; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ local = sdata->local; - - switch (param) { -+ case PRISM2_PARAM_MGMT_IF: -+ if (value == 1) { -+ if (!local->apdev) -+ ret = ieee80211_if_add_mgmt(local); -+ } else if (value == 0) { -+ if (local->apdev) -+ ieee80211_if_del_mgmt(local); -+ } else -+ ret = -EINVAL; -+ break; - default: - ret = -EOPNOTSUPP; - break; -@@ -864,12 +877,20 @@ - void *wrqu, char *extra) - { - struct ieee80211_sub_if_data *sdata; -+ struct ieee80211_local *local; - int *param = (int *) extra; - int ret = 0; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ local = sdata->local; - - switch (*param) { -+ case PRISM2_PARAM_MGMT_IF: -+ if (local->apdev) -+ *param = local->apdev->ifindex; -+ else -+ ret = -ENOENT; -+ break; - default: - ret = -EOPNOTSUPP; - break; diff --git a/package/mac80211/patches/011-allow-ap-vlan-modes.patch b/package/mac80211/patches/011-allow-ap-vlan-modes.patch deleted file mode 100644 index d0edfe835c..0000000000 --- a/package/mac80211/patches/011-allow-ap-vlan-modes.patch +++ /dev/null @@ -1,37 +0,0 @@ -Subject: mac80211: allow AP and VLAN modes - -This adds AP/VLAN modes to the list of modes that a mac80211 -interface can be created in/switched into. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - net/mac80211/cfg.c | 4 ++++ - net/mac80211/ieee80211_ioctl.c | 3 +++ - 2 files changed, 7 insertions(+) - ---- everything.orig/net/mac80211/cfg.c 2007-10-30 15:33:43.227379286 +0100 -+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:27.981515569 +0100 -@@ -25,6 +25,10 @@ nl80211_type_to_mac80211_type(enum nl802 - return IEEE80211_IF_TYPE_STA; - case NL80211_IFTYPE_MONITOR: - return IEEE80211_IF_TYPE_MNTR; -+ case NL80211_IFTYPE_AP: -+ return IEEE80211_IF_TYPE_AP; -+ case NL80211_IFTYPE_AP_VLAN: -+ return IEEE80211_IF_TYPE_VLAN; - default: - return IEEE80211_IF_TYPE_INVALID; - } ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:25.851524684 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:27.981515569 +0100 -@@ -284,6 +284,9 @@ static int ieee80211_ioctl_siwmode(struc - case IW_MODE_MONITOR: - type = IEEE80211_IF_TYPE_MNTR; - break; -+ case IW_MODE_MASTER: -+ type = IEEE80211_IF_TYPE_AP; -+ break; - default: - return -EINVAL; - } diff --git a/package/mac80211/patches/012-mac80211-allow-wds.patch b/package/mac80211/patches/012-mac80211-allow-wds.patch deleted file mode 100644 index d5c57cd019..0000000000 --- a/package/mac80211/patches/012-mac80211-allow-wds.patch +++ /dev/null @@ -1,22 +0,0 @@ -Subject: mac80211: allow WDS mode - -This allows creating interfaces in WDS mode or switching -existing ones into WDS mode (both via cfg80211.) - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - net/mac80211/cfg.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:27.981515569 +0100 -+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:29.441515732 +0100 -@@ -29,6 +29,8 @@ nl80211_type_to_mac80211_type(enum nl802 - return IEEE80211_IF_TYPE_AP; - case NL80211_IFTYPE_AP_VLAN: - return IEEE80211_IF_TYPE_VLAN; -+ case NL80211_IFTYPE_WDS: -+ return IEEE80211_IF_TYPE_WDS; - default: - return IEEE80211_IF_TYPE_INVALID; - } diff --git a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch b/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch deleted file mode 100644 index d418ad3497..0000000000 --- a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- - net/mac80211/ieee80211_ioctl.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:27.981515569 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:30.781513182 +0100 -@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param( - local = sdata->local; - - switch (param) { -+ case PRISM2_PARAM_AP_BRIDGE_PACKETS: -+ local->bridge_packets = value; -+ break; - case PRISM2_PARAM_MGMT_IF: - if (value == 1) { - if (!local->apdev) -@@ -914,6 +917,9 @@ static int ieee80211_ioctl_get_prism2_pa - local = sdata->local; - - switch (*param) { -+ case PRISM2_PARAM_AP_BRIDGE_PACKETS: -+ *param = local->bridge_packets; -+ break; - case PRISM2_PARAM_MGMT_IF: - if (local->apdev) - *param = local->apdev->ifindex; diff --git a/package/mac80211/patches/014-prism2-ioctl-8021x.patch b/package/mac80211/patches/014-prism2-ioctl-8021x.patch deleted file mode 100644 index 5feb01ea32..0000000000 --- a/package/mac80211/patches/014-prism2-ioctl-8021x.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- - net/mac80211/ieee80211_ioctl.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:30.781513182 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:32.281514919 +0100 -@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param( - local = sdata->local; - - switch (param) { -+ case PRISM2_PARAM_IEEE_802_1X: -+ sdata->ieee802_1x = value; -+ break; - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - local->bridge_packets = value; - break; -@@ -917,6 +920,9 @@ static int ieee80211_ioctl_get_prism2_pa - local = sdata->local; - - switch (*param) { -+ case PRISM2_PARAM_IEEE_802_1X: -+ *param = sdata->ieee802_1x; -+ break; - case PRISM2_PARAM_AP_BRIDGE_PACKETS: - *param = local->bridge_packets; - break; diff --git a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch b/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch deleted file mode 100644 index d6e5dfd073..0000000000 --- a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch +++ /dev/null @@ -1,122 +0,0 @@ ---- - net/mac80211/ieee80211_ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 102 insertions(+) - ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:32.281514919 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:33.681513453 +0100 -@@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru - return -EOPNOTSUPP; - } - -+/* -+ * Wow. This ioctl interface is such crap, it's tied -+ * to internal definitions. I hope it dies soon. -+ */ -+static int mode_to_hostapd_mode(enum ieee80211_phymode mode) -+{ -+ switch (mode) { -+ case MODE_IEEE80211A: -+ return 0; -+ case MODE_IEEE80211B: -+ return 1; -+ case MODE_IEEE80211G: -+ return 3; -+ case NUM_IEEE80211_MODES: -+ WARN_ON(1); -+ break; -+ } -+ WARN_ON(1); -+ return -1; -+} -+ -+static int channel_flags_to_hostapd_flags(int flags) -+{ -+ int res = 0; -+ -+ if (flags & IEEE80211_CHAN_W_SCAN) -+ res |= 1; -+ if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN) -+ res |= 2; -+ if (flags & IEEE80211_CHAN_W_IBSS) -+ res |= 4; -+ -+ return res; -+} -+ -+struct ieee80211_channel_data { -+ short chan; /* channel number (IEEE 802.11) */ -+ short freq; /* frequency in MHz */ -+ int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ -+}; -+ -+struct ieee80211_rate_data { -+ int rate; /* rate in 100 kbps */ -+ int flags; /* IEEE80211_RATE_ flags */ -+}; -+ -+static int ieee80211_ioctl_get_hw_features(struct net_device *dev, -+ struct prism2_hostapd_param *param, -+ int param_len) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ u8 *pos = param->u.hw_features.data; -+ int left = param_len - (pos - (u8 *) param); -+ int i; -+ struct hostapd_ioctl_hw_modes_hdr *hdr; -+ struct ieee80211_rate_data *rate; -+ struct ieee80211_channel_data *chan; -+ struct ieee80211_hw_mode *mode; -+ -+ param->u.hw_features.flags = 0; -+ -+ param->u.hw_features.num_modes = 0; -+ list_for_each_entry(mode, &local->modes_list, list) { -+ int clen, rlen; -+ -+ param->u.hw_features.num_modes++; -+ clen = -+ mode->num_channels * sizeof(struct ieee80211_channel_data); -+ rlen = mode->num_rates * sizeof(struct ieee80211_rate_data); -+ if (left < sizeof(*hdr) + clen + rlen) -+ return -E2BIG; -+ left -= sizeof(*hdr) + clen + rlen; -+ -+ hdr = (struct hostapd_ioctl_hw_modes_hdr *)pos; -+ hdr->mode = mode_to_hostapd_mode(mode->mode); -+ hdr->num_channels = mode->num_channels; -+ hdr->num_rates = mode->num_rates; -+ -+ pos = (u8 *) (hdr + 1); -+ chan = (struct ieee80211_channel_data *)pos; -+ for (i = 0; i < mode->num_channels; i++) { -+ chan[i].chan = mode->channels[i].chan; -+ chan[i].freq = mode->channels[i].freq; -+ chan[i].flag = channel_flags_to_hostapd_flags( -+ mode->channels[i].flag); -+ } -+ pos += clen; -+ -+ rate = (struct ieee80211_rate_data *)pos; -+ for (i = 0; i < mode->num_rates; i++) { -+ rate[i].rate = mode->rates[i].rate; -+ rate[i].flags = mode->rates[i].flags; -+ } -+ pos += rlen; -+ } -+ -+ return 0; -+} -+ - - static int ieee80211_ioctl_priv_hostapd(struct net_device *dev, - struct iw_point *p) -@@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd( - } - - switch (param->cmd) { -+ case PRISM2_HOSTAPD_GET_HW_FEATURES: -+ ret = ieee80211_ioctl_get_hw_features(dev, param, p->length); -+ break; - default: - ret = -EOPNOTSUPP; - break; diff --git a/package/mac80211/patches/016-prism2-ioctl-eapol.patch b/package/mac80211/patches/016-prism2-ioctl-eapol.patch deleted file mode 100644 index 5ce57587ab..0000000000 --- a/package/mac80211/patches/016-prism2-ioctl-eapol.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- - net/mac80211/ieee80211_ioctl.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- everything.orig/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:33.681513453 +0100 -+++ everything/net/mac80211/ieee80211_ioctl.c 2007-11-07 13:19:35.171517576 +0100 -@@ -984,6 +984,9 @@ static int ieee80211_ioctl_prism2_param( - local = sdata->local; - - switch (param) { -+ case PRISM2_PARAM_EAPOL: -+ sdata->eapol = value; -+ break; - case PRISM2_PARAM_IEEE_802_1X: - sdata->ieee802_1x = value; - break; -@@ -1022,6 +1025,9 @@ static int ieee80211_ioctl_get_prism2_pa - local = sdata->local; - - switch (*param) { -+ case PRISM2_PARAM_EAPOL: -+ *param = sdata->eapol; -+ break; - case PRISM2_PARAM_IEEE_802_1X: - *param = sdata->ieee802_1x; - break; diff --git a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch b/package/mac80211/patches/017-nl80211-add-key-mgmt.patch deleted file mode 100644 index f5b1d45c15..0000000000 --- a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch +++ /dev/null @@ -1,470 +0,0 @@ -Subject: cfg80211/nl80211: introduce key handling - -This introduces key handling to cfg80211/nl80211. Default -and group keys can be added, changed and removed; sequence -counters for each key can be retrieved. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - include/linux/nl80211.h | 34 +++++ - include/net/cfg80211.h | 44 +++++++ - net/wireless/core.c | 3 - net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 370 insertions(+) - ---- everything.orig/include/linux/nl80211.h 2007-10-30 15:33:43.587381346 +0100 -+++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100 -@@ -37,6 +37,16 @@ - * userspace to request deletion of a virtual interface, then requires - * attribute %NL80211_ATTR_IFINDEX. - * -+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified -+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. -+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or -+ * %NL80211_ATTR_KEY_THRESHOLD. -+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, -+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER -+ * attributes. -+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX -+ * or %NL80211_ATTR_MAC. -+ * - * @NL80211_CMD_MAX: highest used command number - * @__NL80211_CMD_AFTER_LAST: internal use - */ -@@ -54,6 +64,11 @@ enum nl80211_commands { - NL80211_CMD_NEW_INTERFACE, - NL80211_CMD_DEL_INTERFACE, - -+ NL80211_CMD_GET_KEY, -+ NL80211_CMD_SET_KEY, -+ NL80211_CMD_NEW_KEY, -+ NL80211_CMD_DEL_KEY, -+ - /* add commands here */ - - /* used to define NL80211_CMD_MAX below */ -@@ -75,6 +90,17 @@ enum nl80211_commands { - * @NL80211_ATTR_IFNAME: network interface name - * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype - * -+ * @NL80211_ATTR_MAC: MAC address (various uses) -+ * -+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of -+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC -+ * keys -+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) -+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 -+ * section 7.3.2.25.1, e.g. 0x000FAC04) -+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and -+ * CCMP keys, each six bytes in little endian -+ * - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use - */ -@@ -89,6 +115,14 @@ enum nl80211_attrs { - NL80211_ATTR_IFNAME, - NL80211_ATTR_IFTYPE, - -+ NL80211_ATTR_MAC, -+ -+ NL80211_ATTR_KEY_DATA, -+ NL80211_ATTR_KEY_IDX, -+ NL80211_ATTR_KEY_CIPHER, -+ NL80211_ATTR_KEY_SEQ, -+ NL80211_ATTR_KEY_DEFAULT, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, ---- everything.orig/net/wireless/nl80211.c 2007-10-30 15:33:43.637380153 +0100 -+++ everything/net/wireless/nl80211.c 2007-11-07 13:19:38.201511066 +0100 -@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[ - [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, - [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, - [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, -+ -+ [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, -+ -+ [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, -+ .len = WLAN_MAX_KEY_LEN }, -+ [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, -+ [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, -+ [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, - }; - - /* message building helper */ -@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct - return err; - } - -+struct get_key_cookie { -+ struct sk_buff *msg; -+ int error; -+}; -+ -+static void get_key_callback(void *c, struct key_params *params) -+{ -+ struct get_key_cookie *cookie = c; -+ -+ if (params->key) -+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, -+ params->key_len, params->key); -+ -+ if (params->seq) -+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, -+ params->seq_len, params->seq); -+ -+ if (params->cipher) -+ NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, -+ params->cipher); -+ -+ return; -+ nla_put_failure: -+ cookie->error = 1; -+} -+ -+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) -+{ -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ u8 key_idx = 0; -+ u8 *mac_addr = NULL; -+ struct get_key_cookie cookie = { -+ .error = 0, -+ }; -+ void *hdr; -+ struct sk_buff *msg; -+ -+ if (info->attrs[NL80211_ATTR_KEY_IDX]) -+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); -+ -+ if (key_idx > 3) -+ return -EINVAL; -+ -+ if (info->attrs[NL80211_ATTR_MAC]) -+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); -+ -+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev); -+ if (err) -+ return err; -+ -+ if (!drv->ops->get_key) { -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); -+ if (!msg) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, -+ NL80211_CMD_NEW_KEY); -+ -+ if (IS_ERR(hdr)) { -+ err = PTR_ERR(hdr); -+ goto out; -+ } -+ -+ cookie.msg = msg; -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); -+ if (mac_addr) -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); -+ -+ rtnl_lock(); -+ err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, -+ &cookie, get_key_callback); -+ rtnl_unlock(); -+ -+ if (err) -+ goto out; -+ -+ if (cookie.error) -+ goto nla_put_failure; -+ -+ genlmsg_end(msg, hdr); -+ err = genlmsg_unicast(msg, info->snd_pid); -+ goto out; -+ -+ nla_put_failure: -+ err = -ENOBUFS; -+ nlmsg_free(msg); -+ out: -+ cfg80211_put_dev(drv); -+ dev_put(dev); -+ return err; -+} -+ -+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) -+{ -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ u8 key_idx; -+ -+ if (!info->attrs[NL80211_ATTR_KEY_IDX]) -+ return -EINVAL; -+ -+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); -+ -+ if (key_idx > 3) -+ return -EINVAL; -+ -+ /* currently only support setting default key */ -+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) -+ return -EINVAL; -+ -+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev); -+ if (err) -+ return err; -+ -+ if (!drv->ops->set_default_key) { -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ rtnl_lock(); -+ err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); -+ rtnl_unlock(); -+ -+ out: -+ cfg80211_put_dev(drv); -+ dev_put(dev); -+ return err; -+} -+ -+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) -+{ -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ struct key_params params; -+ u8 key_idx = 0; -+ u8 *mac_addr = NULL; -+ -+ memset(¶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 */ diff --git a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch b/package/mac80211/patches/018-mac80211-cfg80211-keys.patch deleted file mode 100644 index 0c98623a2d..0000000000 --- a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch +++ /dev/null @@ -1,120 +0,0 @@ -Subject: mac80211: support adding/removing keys via cfg80211 - -This adds the necessary hooks to mac80211 to allow userspace -to edit keys with cfg80211 (through nl80211.) - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - net/mac80211/cfg.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 91 insertions(+) - ---- everything.orig/net/mac80211/cfg.c 2007-11-07 13:19:29.441515732 +0100 -+++ everything/net/mac80211/cfg.c 2007-11-07 13:19:39.531517685 +0100 -@@ -6,6 +6,7 @@ - * This file is GPLv2 as found in COPYING. - */ - -+#include <linux/ieee80211.h> - #include <linux/nl80211.h> - #include <linux/rtnetlink.h> - #include <net/net_namespace.h> -@@ -105,8 +106,98 @@ static int ieee80211_change_iface(struct - return 0; - } - -+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, u8 *mac_addr, -+ struct key_params *params) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ struct sta_info *sta = NULL; -+ enum ieee80211_key_alg alg; -+ int ret; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ -+ switch (params->cipher) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ alg = ALG_WEP; -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ alg = ALG_TKIP; -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ alg = ALG_CCMP; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (mac_addr) { -+ sta = sta_info_get(sdata->local, mac_addr); -+ if (!sta) -+ return -ENOENT; -+ } -+ -+ ret = 0; -+ if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, -+ params->key_len, params->key)) -+ ret = -ENOMEM; -+ -+ if (sta) -+ sta_info_put(sta); -+ -+ return ret; -+} -+ -+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, u8 *mac_addr) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ struct sta_info *sta; -+ int ret; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ -+ if (mac_addr) { -+ sta = sta_info_get(sdata->local, mac_addr); -+ if (!sta) -+ return -ENOENT; -+ -+ ret = 0; -+ if (sta->key) -+ ieee80211_key_free(sta->key); -+ else -+ ret = -ENOENT; -+ -+ sta_info_put(sta); -+ return ret; -+ } -+ -+ if (!sdata->keys[key_idx]) -+ return -ENOENT; -+ -+ ieee80211_key_free(sdata->keys[key_idx]); -+ -+ return 0; -+} -+ -+static int ieee80211_config_default_key(struct wiphy *wiphy, -+ struct net_device *dev, -+ u8 key_idx) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ ieee80211_set_default_key(sdata, key_idx); -+ -+ return 0; -+} -+ - struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, - .change_virtual_intf = ieee80211_change_iface, -+ .add_key = ieee80211_add_key, -+ .del_key = ieee80211_del_key, -+ .set_default_key = ieee80211_config_default_key, - }; diff --git a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch b/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch deleted file mode 100644 index 5d0020b7fe..0000000000 --- a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch +++ /dev/null @@ -1,161 +0,0 @@ -Subject: mac80211: support getting key sequence counters via cfg80211 - -This implements cfg80211's get_key() to allow retrieving the sequence -counter for a TKIP or CCMP key from userspace. It also cleans up and -documents the associated low-level driver interface. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - include/net/mac80211.h | 14 ++------ - net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 89 insertions(+), 10 deletions(-) - -Index: mac80211/net/mac80211/cfg.c -=================================================================== ---- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:46:41.497954646 +0100 -+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:46:51.346515884 +0100 -@@ -1,7 +1,7 @@ - /* - * mac80211 configuration hooks for cfg80211 - * -- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> -+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> - * - * This file is GPLv2 as found in COPYING. - */ -@@ -180,6 +180,88 @@ - return 0; - } - -+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, u8 *mac_addr, void *cookie, -+ void (*callback)(void *cookie, -+ struct key_params *params)) -+{ -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct sta_info *sta = NULL; -+ u8 seq[6] = {0}; -+ struct key_params params; -+ struct ieee80211_key *key; -+ u32 iv32; -+ u16 iv16; -+ int err = -ENOENT; -+ -+ if (mac_addr) { -+ sta = sta_info_get(sdata->local, mac_addr); -+ if (!sta) -+ goto out; -+ -+ key = sta->key; -+ } else -+ key = sdata->keys[key_idx]; -+ -+ if (!key) -+ goto out; -+ -+ memset(¶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, diff --git a/package/mac80211/patches/020-nl80211-beacon-parameters.patch b/package/mac80211/patches/020-nl80211-beacon-parameters.patch deleted file mode 100644 index 51836f332f..0000000000 --- a/package/mac80211/patches/020-nl80211-beacon-parameters.patch +++ /dev/null @@ -1,279 +0,0 @@ -Subject: cfg80211/nl80211: add beacon settings - -This adds the necessary API to cfg80211/nl80211 to allow -changing beaconing settings. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - include/linux/nl80211.h | 24 ++++++++ - include/net/cfg80211.h | 33 +++++++++++ - net/wireless/nl80211.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 190 insertions(+) - ---- everything.orig/include/net/cfg80211.h 2007-11-08 11:50:57.412840007 +0100 -+++ everything/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100 -@@ -69,6 +69,26 @@ struct key_params { - u32 cipher; - }; - -+/** -+ * struct beacon_parameters - beacon parameters -+ * -+ * Used to configure the beacon for an interface. -+ * -+ * @head: head portion of beacon (before TIM IE) -+ * or %NULL if not changed -+ * @tail: tail portion of beacon (after TIM IE) -+ * or %NULL if not changed -+ * @interval: beacon interval or zero if not changed -+ * @dtim_period: DTIM period or zero if not changed -+ * @head_len: length of @head -+ * @tail_len: length of @tail -+ */ -+struct beacon_parameters { -+ u8 *head, *tail; -+ int interval, dtim_period; -+ int head_len, tail_len; -+}; -+ - /* from net/wireless.h */ - struct wiphy; - -@@ -103,6 +123,13 @@ struct wiphy; - * and @key_index - * - * @set_default_key: set the default key on an interface -+ * -+ * @add_beacon: Add a beacon with given parameters, @head, @interval -+ * and @dtim_period will be valid, @tail is optional. -+ * @set_beacon: Change the beacon parameters for an access point mode -+ * interface. This should reject the call when no beacon has been -+ * configured. -+ * @del_beacon: Remove beacon configuration and stop sending the beacon. - */ - struct cfg80211_ops { - int (*add_virtual_intf)(struct wiphy *wiphy, char *name, -@@ -122,6 +149,12 @@ struct cfg80211_ops { - int (*set_default_key)(struct wiphy *wiphy, - struct net_device *netdev, - u8 key_index); -+ -+ int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *info); -+ int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *info); -+ int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); - }; - - #endif /* __NET_CFG80211_H */ ---- everything.orig/include/linux/nl80211.h 2007-11-08 11:50:57.362839952 +0100 -+++ everything/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100 -@@ -47,6 +47,15 @@ - * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX - * or %NL80211_ATTR_MAC. - * -+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a -+ * %NL80222_CMD_NEW_BEACON message) -+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface -+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, -+ * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. -+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, -+ * parameters are like for %NL80211_CMD_SET_BEACON. -+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it -+ * - * @NL80211_CMD_MAX: highest used command number - * @__NL80211_CMD_AFTER_LAST: internal use - */ -@@ -69,6 +78,11 @@ enum nl80211_commands { - NL80211_CMD_NEW_KEY, - NL80211_CMD_DEL_KEY, - -+ NL80211_CMD_GET_BEACON, -+ NL80211_CMD_SET_BEACON, -+ NL80211_CMD_NEW_BEACON, -+ NL80211_CMD_DEL_BEACON, -+ - /* add commands here */ - - /* used to define NL80211_CMD_MAX below */ -@@ -101,6 +115,11 @@ enum nl80211_commands { - * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and - * CCMP keys, each six bytes in little endian - * -+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU -+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing -+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE -+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE -+ * - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use - */ -@@ -123,6 +142,11 @@ enum nl80211_attrs { - NL80211_ATTR_KEY_SEQ, - NL80211_ATTR_KEY_DEFAULT, - -+ NL80211_ATTR_BEACON_INTERVAL, -+ NL80211_ATTR_DTIM_PERIOD, -+ NL80211_ATTR_BEACON_HEAD, -+ NL80211_ATTR_BEACON_TAIL, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, ---- everything.orig/net/wireless/nl80211.c 2007-11-08 11:50:57.382836589 +0100 -+++ everything/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100 -@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[ - [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, - [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, - [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, -+ -+ [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, -+ [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, -+ [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, -+ .len = IEEE80211_MAX_DATA_LEN }, -+ [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, -+ .len = IEEE80211_MAX_DATA_LEN }, - }; - - /* message building helper */ -@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf - return err; - } - -+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) -+{ -+ int (*call)(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *info); -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ struct beacon_parameters params; -+ int haveinfo = 0; -+ -+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev); -+ if (err) -+ return err; -+ -+ switch (info->genlhdr->cmd) { -+ case NL80211_CMD_NEW_BEACON: -+ /* these are required for NEW_BEACON */ -+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || -+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] || -+ !info->attrs[NL80211_ATTR_BEACON_HEAD]) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ call = drv->ops->add_beacon; -+ break; -+ case NL80211_CMD_SET_BEACON: -+ call = drv->ops->set_beacon; -+ break; -+ default: -+ WARN_ON(1); -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ if (!call) { -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ memset(¶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 */ diff --git a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch b/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch deleted file mode 100644 index 702c68f98f..0000000000 --- a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch +++ /dev/null @@ -1,484 +0,0 @@ -Subject: mac80211: add beacon configuration via cfg80211 - -This patch implements the cfg80211 hooks for configuring beaconing -on an access point interface in mac80211. While doing so, it fixes -a number of races that could badly crash the machine when the -beacon is changed while being requested by the driver. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- -The dtim_count field should possibly also be part of the beacon -structure, but the possible race there doesn't really matter, -worst thing is that one beacon will be sent with a wrong dtim -count if (and only if) userspace changes the dtim period during -operation. - - net/mac80211/cfg.c | 156 +++++++++++++++++++++++++++++++++++++++++ - net/mac80211/debugfs_netdev.c | 27 ------- - net/mac80211/ieee80211_i.h | 14 ++- - net/mac80211/ieee80211_iface.c | 4 - - net/mac80211/tx.c | 63 ++++++++++------ - 5 files changed, 204 insertions(+), 60 deletions(-) - -Index: mac80211/net/mac80211/cfg.c -=================================================================== ---- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:17:12.837164411 +0100 -+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:18:36.853952256 +0100 -@@ -9,6 +9,7 @@ - #include <linux/ieee80211.h> - #include <linux/nl80211.h> - #include <linux/rtnetlink.h> -+#include <linux/rcupdate.h> - #include <net/cfg80211.h> - #include "ieee80211_i.h" - #include "cfg.h" -@@ -274,6 +275,158 @@ - return 0; - } - -+/* -+ * This handles both adding a beacon and setting new beacon info -+ */ -+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, -+ struct beacon_parameters *params) -+{ -+ struct beacon_data *new, *old; -+ int new_head_len, new_tail_len; -+ int size; -+ int err = -EINVAL; -+ -+ old = sdata->u.ap.beacon; -+ -+ /* head must not be zero-length */ -+ if (params->head && !params->head_len) -+ return -EINVAL; -+ -+ /* -+ * This is a kludge. beacon interval should really be part -+ * of the beacon information. -+ */ -+ if (params->interval) { -+ sdata->local->hw.conf.beacon_int = params->interval; -+ if (ieee80211_hw_config(sdata->local)) -+ return -EINVAL; -+ /* -+ * We updated some parameter so if below bails out -+ * it's not an error. -+ */ -+ err = 0; -+ } -+ -+ /* Need to have a beacon head if we don't have one yet */ -+ if (!params->head && !old) -+ return err; -+ -+ /* sorry, no way to start beaconing without dtim period */ -+ if (!params->dtim_period && !old) -+ return err; -+ -+ /* new or old head? */ -+ if (params->head) -+ new_head_len = params->head_len; -+ else -+ new_head_len = old->head_len; -+ -+ /* new or old tail? */ -+ if (params->tail || !old) -+ /* params->tail_len will be zero for !params->tail */ -+ new_tail_len = params->tail_len; -+ else -+ new_tail_len = old->tail_len; -+ -+ size = sizeof(*new) + new_head_len + new_tail_len; -+ -+ new = kzalloc(size, GFP_KERNEL); -+ if (!new) -+ return -ENOMEM; -+ -+ /* start filling the new info now */ -+ -+ /* new or old dtim period? */ -+ if (params->dtim_period) -+ new->dtim_period = params->dtim_period; -+ else -+ new->dtim_period = old->dtim_period; -+ -+ /* -+ * pointers go into the block we allocated, -+ * memory is | beacon_data | head | tail | -+ */ -+ new->head = ((u8 *) new) + sizeof(*new); -+ new->tail = new->head + new_head_len; -+ new->head_len = new_head_len; -+ new->tail_len = new_tail_len; -+ -+ /* copy in head */ -+ if (params->head) -+ memcpy(new->head, params->head, new_head_len); -+ else -+ memcpy(new->head, old->head, new_head_len); -+ -+ /* copy in optional tail */ -+ if (params->tail) -+ memcpy(new->tail, params->tail, new_tail_len); -+ else -+ if (old) -+ memcpy(new->tail, old->tail, new_tail_len); -+ -+ rcu_assign_pointer(sdata->u.ap.beacon, new); -+ -+ synchronize_rcu(); -+ -+ kfree(old); -+ -+ return ieee80211_if_config_beacon(sdata->dev); -+} -+ -+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *params) -+{ -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct beacon_data *old; -+ -+ if (sdata->type != IEEE80211_IF_TYPE_AP) -+ return -EINVAL; -+ -+ old = sdata->u.ap.beacon; -+ -+ if (old) -+ return -EALREADY; -+ -+ return ieee80211_config_beacon(sdata, params); -+} -+ -+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *params) -+{ -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct beacon_data *old; -+ -+ if (sdata->type != IEEE80211_IF_TYPE_AP) -+ return -EINVAL; -+ -+ old = sdata->u.ap.beacon; -+ -+ if (!old) -+ return -ENOENT; -+ -+ return ieee80211_config_beacon(sdata, params); -+} -+ -+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) -+{ -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct beacon_data *old; -+ -+ if (sdata->type != IEEE80211_IF_TYPE_AP) -+ return -EINVAL; -+ -+ old = sdata->u.ap.beacon; -+ -+ if (!old) -+ return -ENOENT; -+ -+ rcu_assign_pointer(sdata->u.ap.beacon, NULL); -+ synchronize_rcu(); -+ kfree(old); -+ -+ return ieee80211_if_config_beacon(dev); -+} -+ - struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -@@ -282,4 +435,7 @@ - .del_key = ieee80211_del_key, - .get_key = ieee80211_get_key, - .set_default_key = ieee80211_config_default_key, -+ .add_beacon = ieee80211_add_beacon, -+ .set_beacon = ieee80211_set_beacon, -+ .del_beacon = ieee80211_del_beacon, - }; -Index: mac80211/net/mac80211/debugfs_netdev.c -=================================================================== ---- mac80211.orig/net/mac80211/debugfs_netdev.c 2007-10-14 00:42:30.054156000 +0200 -+++ mac80211/net/mac80211/debugfs_netdev.c 2007-11-11 15:18:11.852527505 +0100 -@@ -124,7 +124,6 @@ - - /* AP attributes */ - IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); --IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC); - IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); - IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); - IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); -@@ -138,26 +137,6 @@ - } - __IEEE80211_IF_FILE(num_buffered_multicast); - --static ssize_t ieee80211_if_fmt_beacon_head_len( -- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) --{ -- if (sdata->u.ap.beacon_head) -- return scnprintf(buf, buflen, "%d\n", -- sdata->u.ap.beacon_head_len); -- return scnprintf(buf, buflen, "\n"); --} --__IEEE80211_IF_FILE(beacon_head_len); -- --static ssize_t ieee80211_if_fmt_beacon_tail_len( -- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) --{ -- if (sdata->u.ap.beacon_tail) -- return scnprintf(buf, buflen, "%d\n", -- sdata->u.ap.beacon_tail_len); -- return scnprintf(buf, buflen, "\n"); --} --__IEEE80211_IF_FILE(beacon_tail_len); -- - /* WDS attributes */ - IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); - -@@ -194,14 +173,11 @@ - DEBUGFS_ADD(eapol, ap); - DEBUGFS_ADD(ieee8021_x, ap); - DEBUGFS_ADD(num_sta_ps, ap); -- DEBUGFS_ADD(dtim_period, ap); - DEBUGFS_ADD(dtim_count, ap); - DEBUGFS_ADD(num_beacons, ap); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); - DEBUGFS_ADD(num_buffered_multicast, ap); -- DEBUGFS_ADD(beacon_head_len, ap); -- DEBUGFS_ADD(beacon_tail_len, ap); - } - - static void add_wds_files(struct ieee80211_sub_if_data *sdata) -@@ -287,14 +263,11 @@ - DEBUGFS_DEL(eapol, ap); - DEBUGFS_DEL(ieee8021_x, ap); - DEBUGFS_DEL(num_sta_ps, ap); -- DEBUGFS_DEL(dtim_period, ap); - DEBUGFS_DEL(dtim_count, ap); - DEBUGFS_DEL(num_beacons, ap); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); - DEBUGFS_DEL(num_buffered_multicast, ap); -- DEBUGFS_DEL(beacon_head_len, ap); -- DEBUGFS_DEL(beacon_tail_len, ap); - } - - static void del_wds_files(struct ieee80211_sub_if_data *sdata) -Index: mac80211/net/mac80211/ieee80211_i.h -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100 -+++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:18:11.864528190 +0100 -@@ -190,9 +190,14 @@ - typedef ieee80211_txrx_result (*ieee80211_rx_handler) - (struct ieee80211_txrx_data *rx); - -+struct beacon_data { -+ u8 *head, *tail; -+ int head_len, tail_len; -+ int dtim_period; -+}; -+ - struct ieee80211_if_ap { -- u8 *beacon_head, *beacon_tail; -- int beacon_head_len, beacon_tail_len; -+ struct beacon_data *beacon; - - struct list_head vlans; - -@@ -205,7 +210,7 @@ - u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; - atomic_t num_sta_ps; /* number of stations in PS mode */ - struct sk_buff_head ps_bc_buf; -- int dtim_period, dtim_count; -+ int dtim_count; - int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ - int max_ratectrl_rateidx; /* max TX rateidx for rate control */ - int num_beacons; /* number of TXed beacon frames for this BSS */ -@@ -361,14 +366,11 @@ - struct dentry *eapol; - struct dentry *ieee8021_x; - struct dentry *num_sta_ps; -- struct dentry *dtim_period; - struct dentry *dtim_count; - struct dentry *num_beacons; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - struct dentry *num_buffered_multicast; -- struct dentry *beacon_head_len; -- struct dentry *beacon_tail_len; - } ap; - struct { - struct dentry *channel_use; -Index: mac80211/net/mac80211/ieee80211_iface.c -=================================================================== ---- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100 -+++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:18:11.868528415 +0100 -@@ -187,7 +187,6 @@ - sdata->u.vlan.ap = NULL; - break; - case IEEE80211_IF_TYPE_AP: -- sdata->u.ap.dtim_period = 2; - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - skb_queue_head_init(&sdata->u.ap.ps_bc_buf); -@@ -271,8 +270,7 @@ - } - } - -- kfree(sdata->u.ap.beacon_head); -- kfree(sdata->u.ap.beacon_tail); -+ kfree(sdata->u.ap.beacon); - - while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { - local->total_ps_buffered--; -Index: mac80211/net/mac80211/tx.c -=================================================================== ---- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100 -+++ mac80211/net/mac80211/tx.c 2007-11-11 15:18:11.868528415 +0100 -@@ -1656,7 +1656,8 @@ - - static void ieee80211_beacon_add_tim(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, -- struct sk_buff *skb) -+ struct sk_buff *skb, -+ struct beacon_data *beacon) - { - u8 *pos, *tim; - int aid0 = 0; -@@ -1672,7 +1673,7 @@ - IEEE80211_MAX_AID+1); - - if (bss->dtim_count == 0) -- bss->dtim_count = bss->dtim_period - 1; -+ bss->dtim_count = beacon->dtim_period - 1; - else - bss->dtim_count--; - -@@ -1680,7 +1681,7 @@ - *pos++ = WLAN_EID_TIM; - *pos++ = 4; - *pos++ = bss->dtim_count; -- *pos++ = bss->dtim_period; -+ *pos++ = beacon->dtim_period; - - if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) - aid0 = 1; -@@ -1728,8 +1729,9 @@ - struct ieee80211_if_ap *ap = NULL; - struct ieee80211_rate *rate; - struct rate_control_extra extra; -- u8 *b_head, *b_tail; -- int bh_len, bt_len; -+ struct beacon_data *beacon; -+ -+ rcu_read_lock(); - - bdev = dev_get_by_index(if_id); - if (bdev) { -@@ -1738,37 +1740,35 @@ - dev_put(bdev); - } - -- if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || -- !ap->beacon_head) { -+ beacon = rcu_dereference(ap->beacon); -+ -+ if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) { - #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for idx=%d " - "(%s)\n", if_id, bdev ? bdev->name : "N/A"); - #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ -- return NULL; -+ skb = NULL; -+ goto out; - } - -- /* Assume we are generating the normal beacon locally */ -- b_head = ap->beacon_head; -- b_tail = ap->beacon_tail; -- bh_len = ap->beacon_head_len; -- bt_len = ap->beacon_tail_len; -- -- skb = dev_alloc_skb(local->tx_headroom + -- bh_len + bt_len + 256 /* maximum TIM len */); -+ /* headroom, head length, tail length and maximum TIM length */ -+ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + -+ beacon->tail_len + 256); - if (!skb) -- return NULL; -+ goto out; - - skb_reserve(skb, local->tx_headroom); -- memcpy(skb_put(skb, bh_len), b_head, bh_len); -+ memcpy(skb_put(skb, beacon->head_len), beacon->head, -+ beacon->head_len); - - ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - -- ieee80211_beacon_add_tim(local, ap, skb); -+ ieee80211_beacon_add_tim(local, ap, skb, beacon); - -- if (b_tail) { -- memcpy(skb_put(skb, bt_len), b_tail, bt_len); -- } -+ if (beacon->tail) -+ memcpy(skb_put(skb, beacon->tail_len), beacon->tail, -+ beacon->tail_len); - - if (control) { - memset(&extra, 0, sizeof(extra)); -@@ -1781,7 +1781,8 @@ - "found\n", wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb(skb); -- return NULL; -+ skb = NULL; -+ goto out; - } - - control->tx_rate = -@@ -1796,6 +1797,9 @@ - } - - ap->num_beacons++; -+ -+ out: -+ rcu_read_unlock(); - return skb; - } - EXPORT_SYMBOL(ieee80211_beacon_get); -@@ -1844,6 +1848,7 @@ - struct net_device *bdev; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_ap *bss = NULL; -+ struct beacon_data *beacon; - - bdev = dev_get_by_index(if_id); - if (bdev) { -@@ -1851,9 +1856,19 @@ - bss = &sdata->u.ap; - dev_put(bdev); - } -- if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) -+ -+ if (!bss) - return NULL; - -+ rcu_read_lock(); -+ beacon = rcu_dereference(bss->beacon); -+ -+ if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) { -+ rcu_read_unlock(); -+ return NULL; -+ } -+ rcu_read_unlock(); -+ - if (bss->dtim_count != 0) - return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); diff --git a/package/mac80211/patches/022-nl80211-sta.patch b/package/mac80211/patches/022-nl80211-sta.patch deleted file mode 100644 index 4d08721f82..0000000000 --- a/package/mac80211/patches/022-nl80211-sta.patch +++ /dev/null @@ -1,464 +0,0 @@ -Subject: cfg80211/nl80211: station handling - -This patch adds station handling to cfg80211/nl80211. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - include/linux/nl80211.h | 68 +++++++++++++ - include/net/cfg80211.h | 54 ++++++++++ - net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 358 insertions(+) - ---- everything.orig/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100 -+++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100 -@@ -7,6 +7,18 @@ - */ - - /** -+ * DOC: Station handling -+ * -+ * Stations are added per interface, but a special case exists with VLAN -+ * interfaces. When a station is bound to an AP interface, it may be moved -+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). -+ * The station is still assumed to belong to the AP interface it was added -+ * to. -+ * -+ * TODO: need more info? -+ */ -+ -+/** - * enum nl80211_commands - supported nl80211 commands - * - * @NL80211_CMD_UNSPEC: unspecified command to catch errors -@@ -56,6 +68,16 @@ - * parameters are like for %NL80211_CMD_SET_BEACON. - * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it - * -+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by -+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by -+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the -+ * the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC -+ * or, if no MAC address given, all stations, on the interface identified -+ * by %NL80211_ATTR_IFINDEX. -+ * - * @NL80211_CMD_MAX: highest used command number - * @__NL80211_CMD_AFTER_LAST: internal use - */ -@@ -83,6 +105,11 @@ enum nl80211_commands { - NL80211_CMD_NEW_BEACON, - NL80211_CMD_DEL_BEACON, - -+ NL80211_CMD_GET_STATION, -+ NL80211_CMD_SET_STATION, -+ NL80211_CMD_NEW_STATION, -+ NL80211_CMD_DEL_STATION, -+ - /* add commands here */ - - /* used to define NL80211_CMD_MAX below */ -@@ -120,6 +147,17 @@ enum nl80211_commands { - * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE - * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE - * -+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16) -+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of -+ * &enum nl80211_sta_flags. -+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by -+ * IEEE 802.11 7.3.1.6 (u16). -+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported -+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length -+ * restriction (at most %NL80211_MAX_SUPP_RATES). -+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station -+ * to, or the AP interface the station was originally added to to. -+ * - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use - */ -@@ -147,12 +185,20 @@ enum nl80211_attrs { - NL80211_ATTR_BEACON_HEAD, - NL80211_ATTR_BEACON_TAIL, - -+ NL80211_ATTR_STA_AID, -+ NL80211_ATTR_STA_FLAGS, -+ NL80211_ATTR_STA_LISTEN_INTERVAL, -+ NL80211_ATTR_STA_SUPPORTED_RATES, -+ NL80211_ATTR_STA_VLAN, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, - NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 - }; - -+#define NL80211_MAX_SUPP_RATES 32 -+ - /** - * enum nl80211_iftype - (virtual) interface types - * -@@ -184,4 +230,26 @@ enum nl80211_iftype { - NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 - }; - -+/** -+ * enum nl80211_sta_flags - station flags -+ * -+ * Station flags. When a station is added to an AP interface, it is -+ * assumed to be already associated (and hence authenticated.) -+ * -+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) -+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames -+ * with short barker preamble -+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable -+ */ -+enum nl80211_sta_flags { -+ __NL80211_STA_FLAG_INVALID, -+ NL80211_STA_FLAG_AUTHORIZED, -+ NL80211_STA_FLAG_SHORT_PREAMBLE, -+ NL80211_STA_FLAG_WME, -+ -+ /* keep last */ -+ __NL80211_STA_FLAG_AFTER_LAST, -+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 -+}; -+ - #endif /* __LINUX_NL80211_H */ ---- everything.orig/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100 -+++ everything/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100 -@@ -89,6 +89,47 @@ struct beacon_parameters { - int head_len, tail_len; - }; - -+/** -+ * enum station_flags - station flags -+ * -+ * Station capability flags. Note that these must be the bits -+ * according to the nl80211 flags. -+ * -+ * @STATION_FLAG_CHANGED: station flags were changed -+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) -+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames -+ * with short preambles -+ * @STATION_FLAG_WME: station is WME/QoS capable -+ */ -+enum station_flags { -+ STATION_FLAG_CHANGED = 1<<0, -+ STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, -+ STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, -+ STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, -+}; -+ -+/** -+ * struct station_parameters - station parameters -+ * -+ * Used to change and create a new station. -+ * -+ * @vlan: vlan interface station should belong to -+ * @supported_rates: supported rates in IEEE 802.11 format -+ * (or NULL for no change) -+ * @supported_rates_len: number of supported rates -+ * @station_flags: station flags (see &enum station_flags) -+ * @listen_interval: listen interval or -1 for no change -+ * @aid: AID or zero for no change -+ */ -+struct station_parameters { -+ u8 *supported_rates; -+ struct net_device *vlan; -+ u32 station_flags; -+ int listen_interval; -+ u16 aid; -+ u8 supported_rates_len; -+}; -+ - /* from net/wireless.h */ - struct wiphy; - -@@ -130,6 +171,12 @@ struct wiphy; - * interface. This should reject the call when no beacon has been - * configured. - * @del_beacon: Remove beacon configuration and stop sending the beacon. -+ * -+ * @add_station: Add a new station. -+ * -+ * @del_station: Remove a station; @mac may be NULL to remove all stations. -+ * -+ * @change_station: Modify a given station. - */ - struct cfg80211_ops { - int (*add_virtual_intf)(struct wiphy *wiphy, char *name, -@@ -155,6 +202,13 @@ struct cfg80211_ops { - int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); -+ -+ int (*add_station)(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_parameters *params); -+ int (*del_station)(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac); -+ int (*change_station)(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_parameters *params); - }; - - #endif /* __NET_CFG80211_H */ ---- everything.orig/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100 -+++ everything/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100 -@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[ - .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, -+ [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, -+ [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, -+ [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, -+ [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, -+ .len = NL80211_MAX_SUPP_RATES }, -+ [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, - }; - - /* message building helper */ -@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_ - return err; - } - -+static -+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = { -+ [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, -+ [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, -+ [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, -+}; -+ -+static int parse_station_flags(struct nlattr *nla, u32 *staflags) -+{ -+ struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; -+ int flag; -+ -+ *staflags = 0; -+ -+ if (!nla) -+ return 0; -+ -+ if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, -+ nla, sta_flags_policy)) -+ return -EINVAL; -+ -+ *staflags = STATION_FLAG_CHANGED; -+ -+ for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) -+ if (flags[flag]) -+ *staflags |= (1<<flag); -+ -+ return 0; -+} -+ -+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) -+{ -+ return -EOPNOTSUPP; -+} -+ -+/* -+ * Get vlan interface making sure it is on the right wiphy. -+ */ -+static int get_vlan(struct nlattr *vlanattr, -+ struct cfg80211_registered_device *rdev, -+ struct net_device **vlan) -+{ -+ *vlan = NULL; -+ -+ if (vlanattr) { -+ *vlan = dev_get_by_index(nla_get_u32(vlanattr)); -+ if (!*vlan) -+ return -ENODEV; -+ if (!(*vlan)->ieee80211_ptr) -+ return -EINVAL; -+ if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) -+{ -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ struct station_parameters params; -+ u8 *mac_addr = NULL; -+ -+ memset(¶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 */ diff --git a/package/mac80211/patches/023-mac80211-implement-sta.patch b/package/mac80211/patches/023-mac80211-implement-sta.patch deleted file mode 100644 index 095067676c..0000000000 --- a/package/mac80211/patches/023-mac80211-implement-sta.patch +++ /dev/null @@ -1,224 +0,0 @@ -Subject: mac80211: implement cfg80211's station handling - -This implements station handling from userspace via cfg80211 -in mac80211. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - net/mac80211/cfg.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 192 insertions(+) - ---- everything.orig/net/mac80211/cfg.c 2007-11-08 17:11:52.351521702 +0100 -+++ everything/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100 -@@ -14,6 +14,7 @@ - #include <net/cfg80211.h> - #include "ieee80211_i.h" - #include "cfg.h" -+#include "ieee80211_rate.h" - - static enum ieee80211_if_types - nl80211_type_to_mac80211_type(enum nl80211_iftype type) -@@ -428,6 +429,194 @@ static int ieee80211_del_beacon(struct w - return ieee80211_if_config_beacon(dev); - } - -+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -+struct iapp_layer2_update { -+ u8 da[ETH_ALEN]; /* broadcast */ -+ u8 sa[ETH_ALEN]; /* STA addr */ -+ __be16 len; /* 6 */ -+ u8 dsap; /* 0 */ -+ u8 ssap; /* 0 */ -+ u8 control; -+ u8 xid_info[3]; -+} __attribute__ ((packed)); -+ -+static void ieee80211_send_layer2_update(struct sta_info *sta) -+{ -+ struct iapp_layer2_update *msg; -+ struct sk_buff *skb; -+ -+ /* Send Level 2 Update Frame to update forwarding tables in layer 2 -+ * bridge devices */ -+ -+ skb = dev_alloc_skb(sizeof(*msg)); -+ if (!skb) -+ return; -+ msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); -+ -+ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) -+ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ -+ -+ memset(msg->da, 0xff, ETH_ALEN); -+ memcpy(msg->sa, sta->addr, ETH_ALEN); -+ msg->len = htons(6); -+ msg->dsap = 0; -+ msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ -+ msg->control = 0xaf; /* XID response lsb.1111F101. -+ * F=0 (no poll command; unsolicited frame) */ -+ msg->xid_info[0] = 0x81; /* XID format identifier */ -+ msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ -+ msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ -+ -+ skb->dev = sta->dev; -+ skb->protocol = eth_type_trans(skb, sta->dev); -+ memset(skb->cb, 0, sizeof(skb->cb)); -+ netif_rx(skb); -+} -+ -+static void sta_apply_parameters(struct ieee80211_local *local, -+ struct sta_info *sta, -+ struct station_parameters *params) -+{ -+ u32 rates; -+ int i, j; -+ struct ieee80211_hw_mode *mode; -+ -+ if (params->station_flags & STATION_FLAG_CHANGED) { -+ sta->flags &= ~WLAN_STA_AUTHORIZED; -+ if (params->station_flags & STATION_FLAG_AUTHORIZED) -+ sta->flags |= WLAN_STA_AUTHORIZED; -+ -+ sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; -+ if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) -+ sta->flags |= WLAN_STA_SHORT_PREAMBLE; -+ -+ sta->flags &= ~WLAN_STA_WME; -+ if (params->station_flags & STATION_FLAG_WME) -+ sta->flags |= WLAN_STA_WME; -+ } -+ -+ if (params->aid) { -+ sta->aid = params->aid; -+ if (sta->aid > IEEE80211_MAX_AID) -+ sta->aid = 0; /* XXX: should this be an error? */ -+ } -+ -+ if (params->listen_interval >= 0) -+ sta->listen_interval = params->listen_interval; -+ -+ if (params->supported_rates) { -+ rates = 0; -+ mode = local->oper_hw_mode; -+ for (i = 0; i < params->supported_rates_len; i++) { -+ int rate = (params->supported_rates[i] & 0x7f) * 5; -+ for (j = 0; j < mode->num_rates; j++) { -+ if (mode->rates[j].rate == rate) -+ rates |= BIT(j); -+ } -+ } -+ sta->supp_rates = rates; -+ } -+} -+ -+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_parameters *params) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ struct sta_info *sta; -+ struct ieee80211_sub_if_data *sdata; -+ -+ /* Prevent a race with changing the rate control algorithm */ -+ if (!netif_running(dev)) -+ return -ENETDOWN; -+ -+ /* XXX: get sta belonging to dev */ -+ sta = sta_info_get(local, mac); -+ if (sta) { -+ sta_info_put(sta); -+ return -EEXIST; -+ } -+ -+ if (params->vlan) { -+ sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); -+ -+ if (sdata->type != IEEE80211_IF_TYPE_VLAN || -+ sdata->type != IEEE80211_IF_TYPE_AP) -+ return -EINVAL; -+ } else -+ sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ -+ sta = sta_info_add(local, dev, mac, GFP_KERNEL); -+ if (!sta) -+ return -ENOMEM; -+ -+ sta->dev = sdata->dev; -+ if (sdata->type == IEEE80211_IF_TYPE_VLAN || -+ sdata->type == IEEE80211_IF_TYPE_AP) -+ ieee80211_send_layer2_update(sta); -+ -+ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; -+ -+ sta_apply_parameters(local, sta, params); -+ -+ rate_control_rate_init(sta, local); -+ -+ sta_info_put(sta); -+ -+ return 0; -+} -+ -+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ struct sta_info *sta; -+ -+ if (mac) { -+ /* XXX: get sta belonging to dev */ -+ sta = sta_info_get(local, mac); -+ if (!sta) -+ return -ENOENT; -+ -+ sta_info_free(sta); -+ sta_info_put(sta); -+ } else -+ sta_info_flush(local, dev); -+ -+ return 0; -+} -+ -+static int ieee80211_change_station(struct wiphy *wiphy, -+ struct net_device *dev, -+ u8 *mac, -+ struct station_parameters *params) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ struct sta_info *sta; -+ struct ieee80211_sub_if_data *vlansdata; -+ -+ /* XXX: get sta belonging to dev */ -+ sta = sta_info_get(local, mac); -+ if (!sta) -+ return -ENOENT; -+ -+ if (params->vlan && params->vlan != sta->dev) { -+ vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); -+ -+ if (vlansdata->type != IEEE80211_IF_TYPE_VLAN || -+ vlansdata->type != IEEE80211_IF_TYPE_AP) -+ return -EINVAL; -+ -+ sta->dev = params->vlan; -+ ieee80211_send_layer2_update(sta); -+ } -+ -+ sta_apply_parameters(local, sta, params); -+ -+ sta_info_put(sta); -+ -+ return 0; -+} -+ - struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -@@ -439,4 +628,7 @@ struct cfg80211_ops mac80211_config_ops - .add_beacon = ieee80211_add_beacon, - .set_beacon = ieee80211_set_beacon, - .del_beacon = ieee80211_del_beacon, -+ .add_station = ieee80211_add_station, -+ .del_station = ieee80211_del_station, -+ .change_station = ieee80211_change_station, - }; diff --git a/package/mac80211/patches/024-nl80211-get-sta.patch b/package/mac80211/patches/024-nl80211-get-sta.patch deleted file mode 100644 index 198ad1876b..0000000000 --- a/package/mac80211/patches/024-nl80211-get-sta.patch +++ /dev/null @@ -1,208 +0,0 @@ -Subject: cfg80211/nl80211: implement station attribute retrieval - -After a station is added to the kernel's structures, userspace -has to be able to retrieve statistics about that station, especially -whether the station was idle and how much bytes were transferred -to and from it. This adds the necessary code to nl80211. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - include/linux/nl80211.h | 28 ++++++++++++++++ - include/net/cfg80211.h | 35 ++++++++++++++++++++ - net/wireless/nl80211.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++- - 3 files changed, 144 insertions(+), 1 deletion(-) - ---- everything.orig/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100 -+++ everything/include/linux/nl80211.h 2007-11-08 17:17:00.891547364 +0100 -@@ -157,6 +157,9 @@ enum nl80211_commands { - * restriction (at most %NL80211_MAX_SUPP_RATES). - * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station - * to, or the AP interface the station was originally added to to. -+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info -+ * given for %NL80211_CMD_GET_STATION, nested attribute containing -+ * info as possible, see &enum nl80211_sta_stats. - * - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -190,6 +193,7 @@ enum nl80211_attrs { - NL80211_ATTR_STA_LISTEN_INTERVAL, - NL80211_ATTR_STA_SUPPORTED_RATES, - NL80211_ATTR_STA_VLAN, -+ NL80211_ATTR_STA_STATS, - - /* add attributes here, update the policy in nl80211.c */ - -@@ -252,4 +256,28 @@ enum nl80211_sta_flags { - NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 - }; - -+/** -+ * enum nl80211_sta_stats - station statistics -+ * -+ * These attribute types are used with %NL80211_ATTR_STA_STATS -+ * when getting information about a station. -+ * -+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved -+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) -+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) -+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) -+ * @__NL80211_STA_STAT_AFTER_LAST: internal -+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute -+ */ -+enum nl80211_sta_stats { -+ __NL80211_STA_STAT_INVALID, -+ NL80211_STA_STAT_INACTIVE_TIME, -+ NL80211_STA_STAT_RX_BYTES, -+ NL80211_STA_STAT_TX_BYTES, -+ -+ /* keep last */ -+ __NL80211_STA_STAT_AFTER_LAST, -+ NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 -+}; -+ - #endif /* __LINUX_NL80211_H */ ---- everything.orig/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100 -+++ everything/include/net/cfg80211.h 2007-11-08 17:17:00.891547364 +0100 -@@ -130,6 +130,39 @@ struct station_parameters { - u8 supported_rates_len; - }; - -+/** -+ * enum station_stats_flags - station statistics flags -+ * -+ * Used by the driver to indicate which info in &struct station_stats -+ * it has filled in during get_station(). -+ * -+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled -+ * @STATION_STAT_RX_BYTES: @rx_bytes filled -+ * @STATION_STAT_TX_BYTES: @tx_bytes filled -+ */ -+enum station_stats_flags { -+ STATION_STAT_INACTIVE_TIME = 1<<0, -+ STATION_STAT_RX_BYTES = 1<<1, -+ STATION_STAT_TX_BYTES = 1<<2, -+}; -+ -+/** -+ * struct station_stats - station statistics -+ * -+ * Station information filled by driver for get_station(). -+ * -+ * @filled: bitflag of flags from &enum station_stats_flags -+ * @inactive_time: time since last station activity (tx/rx) in milliseconds -+ * @rx_bytes: bytes received from this station -+ * @tx_bytes: bytes transmitted to this station -+ */ -+struct station_stats { -+ u32 filled; -+ u32 inactive_time; -+ u32 rx_bytes; -+ u32 tx_bytes; -+}; -+ - /* from net/wireless.h */ - struct wiphy; - -@@ -209,6 +242,8 @@ struct cfg80211_ops { - u8 *mac); - int (*change_station)(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_parameters *params); -+ int (*get_station)(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_stats *stats); - }; - - #endif /* __NET_CFG80211_H */ ---- everything.orig/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100 -+++ everything/net/wireless/nl80211.c 2007-11-08 17:17:00.901534235 +0100 -@@ -751,9 +751,89 @@ static int parse_station_flags(struct nl - return 0; - } - -+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, -+ int flags, struct net_device *dev, -+ u8 *mac_addr, struct station_stats *stats) -+{ -+ void *hdr; -+ struct nlattr *statsattr; -+ -+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); -+ if (!hdr) -+ return -1; -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); -+ -+ statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); -+ if (!statsattr) -+ goto nla_put_failure; -+ if (stats->filled & STATION_STAT_INACTIVE_TIME) -+ NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, -+ stats->inactive_time); -+ if (stats->filled & STATION_STAT_RX_BYTES) -+ NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, -+ stats->rx_bytes); -+ if (stats->filled & STATION_STAT_TX_BYTES) -+ NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, -+ stats->tx_bytes); -+ -+ nla_nest_end(msg, statsattr); -+ -+ return genlmsg_end(msg, hdr); -+ -+ nla_put_failure: -+ return genlmsg_cancel(msg, hdr); -+} -+ -+ - static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) - { -- return -EOPNOTSUPP; -+ struct cfg80211_registered_device *drv; -+ int err; -+ struct net_device *dev; -+ struct station_stats stats; -+ struct sk_buff *msg; -+ u8 *mac_addr = NULL; -+ -+ memset(&stats, 0, sizeof(stats)); -+ -+ if (!info->attrs[NL80211_ATTR_MAC]) -+ return -EINVAL; -+ -+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); -+ -+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev); -+ if (err) -+ return err; -+ -+ if (!drv->ops->get_station) { -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ rtnl_lock(); -+ err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); -+ rtnl_unlock(); -+ -+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); -+ if (!msg) -+ goto out; -+ -+ if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, -+ dev, mac_addr, &stats) < 0) -+ goto out_free; -+ -+ err = genlmsg_unicast(msg, info->snd_pid); -+ goto out; -+ -+ out_free: -+ nlmsg_free(msg); -+ -+ out: -+ cfg80211_put_dev(drv); -+ dev_put(dev); -+ return err; - } - - /* diff --git a/package/mac80211/patches/025-mac80211-get-sta.patch b/package/mac80211/patches/025-mac80211-get-sta.patch deleted file mode 100644 index 868ca86fa3..0000000000 --- a/package/mac80211/patches/025-mac80211-get-sta.patch +++ /dev/null @@ -1,51 +0,0 @@ -Subject: mac80211: implement station stats retrieval - -This implements the required cfg80211 callback in mac80211 -to allow userspace to get station statistics. - -Signed-off-by: Johannes Berg <johannes@sipsolutions.net> - ---- - net/mac80211/cfg.c | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - ---- everything.orig/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100 -+++ everything/net/mac80211/cfg.c 2007-11-08 17:17:01.921529351 +0100 -@@ -617,6 +617,31 @@ static int ieee80211_change_station(stru - return 0; - } - -+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_stats *stats) -+{ -+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -+ struct sta_info *sta; -+ -+ sta = sta_info_get(local, mac); -+ if (!sta) -+ return -ENOENT; -+ -+ /* XXX: verify sta->dev == dev */ -+ -+ stats->filled = STATION_STAT_INACTIVE_TIME | -+ STATION_STAT_RX_BYTES | -+ STATION_STAT_TX_BYTES; -+ -+ stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); -+ stats->rx_bytes = sta->rx_bytes; -+ stats->tx_bytes = sta->tx_bytes; -+ -+ sta_info_put(sta); -+ -+ return 0; -+} -+ - struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -@@ -631,4 +656,5 @@ struct cfg80211_ops mac80211_config_ops - .add_station = ieee80211_add_station, - .del_station = ieee80211_del_station, - .change_station = ieee80211_change_station, -+ .get_station = ieee80211_get_station, - }; diff --git a/package/mac80211/src/include/linux/ieee80211.h b/package/mac80211/src/include/linux/ieee80211.h index 30621c2715..f577c8f1c6 100644 --- a/package/mac80211/src/include/linux/ieee80211.h +++ b/package/mac80211/src/include/linux/ieee80211.h @@ -54,6 +54,8 @@ #define IEEE80211_STYPE_ACTION 0x00D0 /* control */ +#define IEEE80211_STYPE_BACK_REQ 0x0080 +#define IEEE80211_STYPE_BACK 0x0090 #define IEEE80211_STYPE_PSPOLL 0x00A0 #define IEEE80211_STYPE_RTS 0x00B0 #define IEEE80211_STYPE_CTS 0x00C0 @@ -81,18 +83,18 @@ /* miscellaneous IEEE 802.11 constants */ -#define IEEE80211_MAX_FRAG_THRESHOLD 2346 -#define IEEE80211_MAX_RTS_THRESHOLD 2347 +#define IEEE80211_MAX_FRAG_THRESHOLD 2352 +#define IEEE80211_MAX_RTS_THRESHOLD 2353 #define IEEE80211_MAX_AID 2007 #define IEEE80211_MAX_TIM_LEN 251 -#define IEEE80211_MAX_DATA_LEN 2304 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section 6.2.1.1.2. - The figure in section 7.1.2 suggests a body size of up to 2312 - bytes is allowed, which is a bit confusing, I suspect this - represents the 2304 bytes of real data, plus a possible 8 bytes of - WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + 802.11e clarifies the figure in section 7.1.2. The frame body is + up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ +#define IEEE80211_MAX_DATA_LEN 2304 +/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ +#define IEEE80211_MAX_FRAME_LEN 2352 #define IEEE80211_MAX_SSID_LEN 32 @@ -185,6 +187,25 @@ struct ieee80211_mgmt { u8 new_chan; u8 switch_count; } __attribute__((packed)) chan_switch; + struct{ + u8 action_code; + u8 dialog_token; + __le16 capab; + __le16 timeout; + __le16 start_seq_num; + } __attribute__((packed)) addba_req; + struct{ + u8 action_code; + u8 dialog_token; + __le16 status; + __le16 capab; + __le16 timeout; + } __attribute__((packed)) addba_resp; + struct{ + u8 action_code; + __le16 params; + __le16 reason_code; + } __attribute__((packed)) delba; } u; } __attribute__ ((packed)) action; } u; @@ -205,6 +226,72 @@ struct ieee80211_cts { u8 ra[6]; } __attribute__ ((packed)); +/** + * struct ieee80211_bar - HT Block Ack Request + * + * This structure refers to "HT BlockAckReq" as + * described in 802.11n draft section 7.2.1.7.1 + */ +struct ieee80211_bar { + __le16 frame_control; + __le16 duration; + __u8 ra[6]; + __u8 ta[6]; + __le16 control; + __le16 start_seq_num; +} __attribute__((packed)); + +/** + * struct ieee80211_ht_cap - HT capabilities + * + * This structure refers to "HT capabilities element" as + * described in 802.11n draft section 7.3.2.52 + */ +struct ieee80211_ht_cap { + __le16 cap_info; + u8 ampdu_params_info; + u8 supp_mcs_set[16]; + __le16 extended_ht_cap_info; + __le32 tx_BF_cap_info; + u8 antenna_selection_info; +} __attribute__ ((packed)); + +/** + * struct ieee80211_ht_cap - HT additional information + * + * This structure refers to "HT information element" as + * described in 802.11n draft section 7.3.2.53 + */ +struct ieee80211_ht_addt_info { + u8 control_chan; + u8 ht_param; + __le16 operation_mode; + __le16 stbc_param; + u8 basic_set[16]; +} __attribute__ ((packed)); + +/* 802.11n HT capabilities masks */ +#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 +#define IEEE80211_HT_CAP_MIMO_PS 0x000C +#define IEEE80211_HT_CAP_GRN_FLD 0x0010 +#define IEEE80211_HT_CAP_SGI_20 0x0020 +#define IEEE80211_HT_CAP_SGI_40 0x0040 +#define IEEE80211_HT_CAP_DELAY_BA 0x0400 +#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 +#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C +/* 802.11n HT IE masks */ +#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_IE_CHA_WIDTH 0x04 +#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 +#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 +#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 + +/* MIMO Power Save Modes */ +#define WLAN_HT_CAP_MIMO_PS_STATIC 0 +#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 +#define WLAN_HT_CAP_MIMO_PS_INVALID 2 +#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 @@ -271,6 +358,18 @@ enum ieee80211_statuscode { WLAN_STATUS_UNSUPP_RSN_VERSION = 44, WLAN_STATUS_INVALID_RSN_IE_CAP = 45, WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, + /* 802.11e */ + WLAN_STATUS_UNSPECIFIED_QOS = 32, + WLAN_STATUS_ASSOC_DENIED_NOBANDWIDTH = 33, + WLAN_STATUS_ASSOC_DENIED_LOWACK = 34, + WLAN_STATUS_ASSOC_DENIED_UNSUPP_QOS = 35, + WLAN_STATUS_REQUEST_DECLINED = 37, + WLAN_STATUS_INVALID_QOS_PARAM = 38, + WLAN_STATUS_CHANGE_TSPEC = 39, + WLAN_STATUS_WAIT_TS_DELAY = 47, + WLAN_STATUS_NO_DIRECT_LINK = 48, + WLAN_STATUS_STA_NOT_PRESENT = 49, + WLAN_STATUS_STA_NOT_QSTA = 50, }; @@ -301,6 +400,16 @@ enum ieee80211_reasoncode { WLAN_REASON_INVALID_RSN_IE_CAP = 22, WLAN_REASON_IEEE8021X_FAILED = 23, WLAN_REASON_CIPHER_SUITE_REJECTED = 24, + /* 802.11e */ + WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32, + WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33, + WLAN_REASON_DISASSOC_LOW_ACK = 34, + WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP = 35, + WLAN_REASON_QSTA_LEAVE_QBSS = 36, + WLAN_REASON_QSTA_NOT_USE = 37, + WLAN_REASON_QSTA_REQUIRE_SETUP = 38, + WLAN_REASON_QSTA_TIMEOUT = 39, + WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45, }; @@ -319,6 +428,15 @@ enum ieee80211_eid { WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, + /* 802.11e */ + WLAN_EID_QBSS_LOAD = 11, + WLAN_EID_EDCA_PARAM_SET = 12, + WLAN_EID_TSPEC = 13, + WLAN_EID_TCLAS = 14, + WLAN_EID_SCHEDULE = 15, + WLAN_EID_TS_DELAY = 43, + WLAN_EID_TCLAS_PROCESSING = 44, + WLAN_EID_QOS_CAPA = 46, /* 802.11h */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, @@ -333,6 +451,9 @@ enum ieee80211_eid { /* 802.11g */ WLAN_EID_ERP_INFO = 42, WLAN_EID_EXT_SUPP_RATES = 50, + /* 802.11n */ + WLAN_EID_HT_CAPABILITY = 45, + WLAN_EID_HT_EXTRA_INFO = 61, /* 802.11i */ WLAN_EID_RSN = 48, WLAN_EID_WPA = 221, @@ -341,6 +462,32 @@ enum ieee80211_eid { WLAN_EID_QOS_PARAMETER = 222 }; +/* Action category code */ +enum ieee80211_category { + WLAN_CATEGORY_SPECTRUM_MGMT = 0, + WLAN_CATEGORY_QOS = 1, + WLAN_CATEGORY_DLS = 2, + WLAN_CATEGORY_BACK = 3, + WLAN_CATEGORY_WMM = 17, +}; + +/* BACK action code */ +enum ieee80211_back_actioncode { + WLAN_ACTION_ADDBA_REQ = 0, + WLAN_ACTION_ADDBA_RESP = 1, + WLAN_ACTION_DELBA = 2, +}; + +/* BACK (block-ack) parties */ +enum ieee80211_back_parties { + WLAN_BACK_RECIPIENT = 0, + WLAN_BACK_INITIATOR = 1, + WLAN_BACK_TIMER = 2, +}; + +/* A-MSDU 802.11n */ +#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080 + /* cipher suite selectors */ #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 diff --git a/package/mac80211/src/include/linux/nl80211.h b/package/mac80211/src/include/linux/nl80211.h index a5dd030d50..a9f0b93324 100644 --- a/package/mac80211/src/include/linux/nl80211.h +++ b/package/mac80211/src/include/linux/nl80211.h @@ -7,6 +7,18 @@ */ /** + * DOC: Station handling + * + * Stations are added per interface, but a special case exists with VLAN + * interfaces. When a station is bound to an AP interface, it may be moved + * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). + * The station is still assumed to belong to the AP interface it was added + * to. + * + * TODO: need more info? + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -25,7 +37,7 @@ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get * on an %NL80211_ATTR_IFINDEX is supported. * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires - %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also @@ -37,6 +49,35 @@ * userspace to request deletion of a virtual interface, then requires * attribute %NL80211_ATTR_IFINDEX. * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. + * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or + * %NL80211_ATTR_KEY_THRESHOLD. + * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, + * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER + * attributes. + * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX + * or %NL80211_ATTR_MAC. + * + * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a + * %NL80222_CMD_NEW_BEACON message) + * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface + * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, + * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. + * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, + * parameters are like for %NL80211_CMD_SET_BEACON. + * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it + * + * @NL80211_CMD_GET_STATION: Get station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_STATION: Set station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all stations, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -54,6 +95,21 @@ enum nl80211_commands { NL80211_CMD_NEW_INTERFACE, NL80211_CMD_DEL_INTERFACE, + NL80211_CMD_GET_KEY, + NL80211_CMD_SET_KEY, + NL80211_CMD_NEW_KEY, + NL80211_CMD_DEL_KEY, + + NL80211_CMD_GET_BEACON, + NL80211_CMD_SET_BEACON, + NL80211_CMD_NEW_BEACON, + NL80211_CMD_DEL_BEACON, + + NL80211_CMD_GET_STATION, + NL80211_CMD_SET_STATION, + NL80211_CMD_NEW_STATION, + NL80211_CMD_DEL_STATION, + /* add commands here */ /* used to define NL80211_CMD_MAX below */ @@ -75,6 +131,42 @@ enum nl80211_commands { * @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * + * @NL80211_ATTR_MAC: MAC address (various uses) + * + * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) + * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * + * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU + * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing + * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE + * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE + * + * @NL80211_ATTR_STA_AID: Association ID for the station (u16) + * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_sta_flags. + * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by + * IEEE 802.11 7.3.1.6 (u16). + * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported + * rates as defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). + * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station + * to, or the AP interface the station was originally added to to. + * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info + * given for %NL80211_CMD_GET_STATION, nested attribute containing + * info as possible, see &enum nl80211_sta_stats. + * + * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, + * consisting of a nested array. + * + * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_mntr_flags. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -89,12 +181,38 @@ enum nl80211_attrs { NL80211_ATTR_IFNAME, NL80211_ATTR_IFTYPE, + NL80211_ATTR_MAC, + + NL80211_ATTR_KEY_DATA, + NL80211_ATTR_KEY_IDX, + NL80211_ATTR_KEY_CIPHER, + NL80211_ATTR_KEY_SEQ, + NL80211_ATTR_KEY_DEFAULT, + + NL80211_ATTR_BEACON_INTERVAL, + NL80211_ATTR_DTIM_PERIOD, + NL80211_ATTR_BEACON_HEAD, + NL80211_ATTR_BEACON_TAIL, + + NL80211_ATTR_STA_AID, + NL80211_ATTR_STA_FLAGS, + NL80211_ATTR_STA_LISTEN_INTERVAL, + NL80211_ATTR_STA_SUPPORTED_RATES, + NL80211_ATTR_STA_VLAN, + NL80211_ATTR_STA_STATS, + + NL80211_ATTR_WIPHY_BANDS, + + NL80211_ATTR_MNTR_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; +#define NL80211_MAX_SUPP_RATES 32 + /** * enum nl80211_iftype - (virtual) interface types * @@ -126,4 +244,139 @@ enum nl80211_iftype { NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 }; +/** + * enum nl80211_sta_flags - station flags + * + * Station flags. When a station is added to an AP interface, it is + * assumed to be already associated (and hence authenticated.) + * + * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) + * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short barker preamble + * @NL80211_STA_FLAG_WME: station is WME/QoS capable + */ +enum nl80211_sta_flags { + __NL80211_STA_FLAG_INVALID, + NL80211_STA_FLAG_AUTHORIZED, + NL80211_STA_FLAG_SHORT_PREAMBLE, + NL80211_STA_FLAG_WME, + + /* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, + NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sta_stats - station statistics + * + * These attribute types are used with %NL80211_ATTR_STA_STATS + * when getting information about a station. + * + * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved + * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) + * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) + * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) + * @__NL80211_STA_STAT_AFTER_LAST: internal + * @NL80211_STA_STAT_MAX: highest possible station stats attribute + */ +enum nl80211_sta_stats { + __NL80211_STA_STAT_INVALID, + NL80211_STA_STAT_INACTIVE_TIME, + NL80211_STA_STAT_RX_BYTES, + NL80211_STA_STAT_TX_BYTES, + + /* keep last */ + __NL80211_STA_STAT_AFTER_LAST, + NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, + * an array of nested frequency attributes + * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, + * an array of nested bitrate attributes + */ +enum nl80211_band_attr { + __NL80211_BAND_ATTR_INVALID, + NL80211_BAND_ATTR_FREQS, + NL80211_BAND_ATTR_RATES, + + /* keep last */ + __NL80211_BAND_ATTR_AFTER_LAST, + NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_frequency_attr - frequency attributes + * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz + * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current + * regulatory domain. + * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is + * permitted on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory + * on this channel in current regulatory domain. + */ +enum nl80211_frequency_attr { + __NL80211_FREQUENCY_ATTR_INVALID, + NL80211_FREQUENCY_ATTR_FREQ, + NL80211_FREQUENCY_ATTR_DISABLED, + NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, + NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_RADAR, + + /* keep last */ + __NL80211_FREQUENCY_ATTR_AFTER_LAST, + NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_bitrate_attr - bitrate attributes + * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps + * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported + * in 2.4 GHz band. + */ +enum nl80211_bitrate_attr { + __NL80211_BITRATE_ATTR_INVALID, + NL80211_BITRATE_ATTR_RATE, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, + + /* keep last */ + __NL80211_BITRATE_ATTR_AFTER_LAST, + NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mntr_flags - monitor configuration flags + * + * Monitor configuration flags. + * + * @__NL80211_MNTR_FLAG_INVALID: reserved + * + * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS + * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @NL80211_MNTR_FLAG_CONTROL: pass control frames + * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering + * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. + * overrides all other flags. + * + * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use + * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag + */ +enum nl80211_mntr_flags { + __NL80211_MNTR_FLAG_INVALID, + NL80211_MNTR_FLAG_FCSFAIL, + NL80211_MNTR_FLAG_PLCPFAIL, + NL80211_MNTR_FLAG_CONTROL, + NL80211_MNTR_FLAG_OTHER_BSS, + NL80211_MNTR_FLAG_COOK_FRAMES, + + /* keep last */ + __NL80211_MNTR_FLAG_AFTER_LAST, + NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/package/mac80211/src/include/net/cfg80211.h b/package/mac80211/src/include/net/cfg80211.h index d30960e175..ab4caf6395 100644 --- a/package/mac80211/src/include/net/cfg80211.h +++ b/package/mac80211/src/include/net/cfg80211.h @@ -49,6 +49,140 @@ extern int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator); + /** + * struct key_params - key information + * + * Information about a key + * + * @key: key material + * @key_len: length of key material + * @cipher: cipher suite selector + * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used + * with the get_key() callback, must be in little endian, + * length given by @seq_len. + */ +struct key_params { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; + +/** + * struct beacon_parameters - beacon parameters + * + * Used to configure the beacon for an interface. + * + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed + * @tail: tail portion of beacon (after TIM IE) + * or %NULL if not changed + * @interval: beacon interval or zero if not changed + * @dtim_period: DTIM period or zero if not changed + * @head_len: length of @head + * @tail_len: length of @tail + */ +struct beacon_parameters { + u8 *head, *tail; + int interval, dtim_period; + int head_len, tail_len; +}; + +/** + * enum station_flags - station flags + * + * Station capability flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @STATION_FLAG_CHANGED: station flags were changed + * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) + * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short preambles + * @STATION_FLAG_WME: station is WME/QoS capable + */ +enum station_flags { + STATION_FLAG_CHANGED = 1<<0, + STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, + STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, + STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, +}; + +/** + * struct station_parameters - station parameters + * + * Used to change and create a new station. + * + * @vlan: vlan interface station should belong to + * @supported_rates: supported rates in IEEE 802.11 format + * (or NULL for no change) + * @supported_rates_len: number of supported rates + * @station_flags: station flags (see &enum station_flags) + * @listen_interval: listen interval or -1 for no change + * @aid: AID or zero for no change + */ +struct station_parameters { + u8 *supported_rates; + struct net_device *vlan; + u32 station_flags; + int listen_interval; + u16 aid; + u8 supported_rates_len; +}; + +/** + * enum station_stats_flags - station statistics flags + * + * Used by the driver to indicate which info in &struct station_stats + * it has filled in during get_station(). + * + * @STATION_STAT_INACTIVE_TIME: @inactive_time filled + * @STATION_STAT_RX_BYTES: @rx_bytes filled + * @STATION_STAT_TX_BYTES: @tx_bytes filled + */ +enum station_stats_flags { + STATION_STAT_INACTIVE_TIME = 1<<0, + STATION_STAT_RX_BYTES = 1<<1, + STATION_STAT_TX_BYTES = 1<<2, +}; + +/** + * struct station_stats - station statistics + * + * Station information filled by driver for get_station(). + * + * @filled: bitflag of flags from &enum station_stats_flags + * @inactive_time: time since last station activity (tx/rx) in milliseconds + * @rx_bytes: bytes received from this station + * @tx_bytes: bytes transmitted to this station + */ +struct station_stats { + u32 filled; + u32 inactive_time; + u32 rx_bytes; + u32 tx_bytes; +}; + +/** + * enum monitor_flags - monitor flags + * + * Monitor interface configuration flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS + * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @MONITOR_FLAG_CONTROL: pass control frames + * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering + * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + */ +enum monitor_flags { + MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, + MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL, + MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, + MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, + MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, +}; + /* from net/wireless.h */ struct wiphy; @@ -71,13 +205,66 @@ struct wiphy; * * @change_virtual_intf: change type of virtual interface * + * @add_key: add a key with the given parameters. @mac_addr will be %NULL + * when adding a group key. + * + * @get_key: get information about the key with the given parameters. + * @mac_addr will be %NULL when requesting information for a group + * key. All pointers given to the @callback function need not be valid + * after it returns. + * + * @del_key: remove a key given the @mac_addr (%NULL for a group key) + * and @key_index + * + * @set_default_key: set the default key on an interface + * + * @add_beacon: Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @set_beacon: Change the beacon parameters for an access point mode + * interface. This should reject the call when no beacon has been + * configured. + * @del_beacon: Remove beacon configuration and stop sending the beacon. + * + * @add_station: Add a new station. + * + * @del_station: Remove a station; @mac may be NULL to remove all stations. + * + * @change_station: Modify a given station. */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name, - enum nl80211_iftype type); + enum nl80211_iftype type, u32 *flags); int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, - enum nl80211_iftype type); + enum nl80211_iftype type, u32 *flags); + + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, u8 *mac_addr, + struct key_params *params); + int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params*)); + int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, u8 *mac_addr); + int (*set_default_key)(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index); + + int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); + + + int (*add_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*del_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac); + int (*change_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*get_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_stats *stats); }; #endif /* __NET_CFG80211_H */ diff --git a/package/mac80211/src/include/net/mac80211.h b/package/mac80211/src/include/net/mac80211.h index 2b1bffbf5e..460da54a00 100644 --- a/package/mac80211/src/include/net/mac80211.h +++ b/package/mac80211/src/include/net/mac80211.h @@ -69,95 +69,20 @@ * not do so then mac80211 may add this under certain circumstances. */ -#define IEEE80211_CHAN_W_SCAN 0x00000001 -#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002 -#define IEEE80211_CHAN_W_IBSS 0x00000004 - -/* Channel information structure. Low-level driver is expected to fill in chan, - * freq, and val fields. Other fields will be filled in by 80211.o based on - * hostapd information and low-level driver does not need to use them. The - * limits for each channel will be provided in 'struct ieee80211_conf' when - * configuring the low-level driver with hw->config callback. If a device has - * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED - * can be set to let the driver configure all fields */ -struct ieee80211_channel { - short chan; /* channel number (IEEE 802.11) */ - short freq; /* frequency in MHz */ - int val; /* hw specific value for the channel */ - int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ - unsigned char power_level; - unsigned char antenna_max; -}; - -#define IEEE80211_RATE_ERP 0x00000001 -#define IEEE80211_RATE_BASIC 0x00000002 -#define IEEE80211_RATE_PREAMBLE2 0x00000004 -#define IEEE80211_RATE_SUPPORTED 0x00000010 -#define IEEE80211_RATE_OFDM 0x00000020 -#define IEEE80211_RATE_CCK 0x00000040 -#define IEEE80211_RATE_MANDATORY 0x00000100 - -#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2) -#define IEEE80211_RATE_MODULATION(f) \ - (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM)) - -/* Low-level driver should set PREAMBLE2, OFDM and CCK flags. - * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the - * configuration. */ -struct ieee80211_rate { - int rate; /* rate in 100 kbps */ - int val; /* hw specific value for the rate */ - int flags; /* IEEE80211_RATE_ flags */ - int val2; /* hw specific value for the rate when using short preamble - * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for - * 2, 5.5, and 11 Mbps) */ - signed char min_rssi_ack; - unsigned char min_rssi_ack_delta; - - /* following fields are set by 80211.o and need not be filled by the - * low-level driver */ - int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for - * optimizing channel utilization estimates */ -}; - /** - * enum ieee80211_phymode - PHY modes + * struct ieee80211_ht_bss_info - describing BSS's HT characteristics * - * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h - * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b - * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM), - * backwards compatible with 11b mode - * @NUM_IEEE80211_MODES: internal - */ -enum ieee80211_phymode { - MODE_IEEE80211A, - MODE_IEEE80211B, - MODE_IEEE80211G, - - /* keep last */ - NUM_IEEE80211_MODES -}; - -/** - * struct ieee80211_hw_mode - PHY mode definition - * - * This structure describes the capabilities supported by the device - * in a single PHY mode. + * This structure describes most essential parameters needed + * to describe 802.11n HT characteristics in a BSS * - * @mode: the PHY mode for this definition - * @num_channels: number of supported channels - * @channels: pointer to array of supported channels - * @num_rates: number of supported bitrates - * @rates: pointer to array of supported bitrates - * @list: internal + * @primary_channel: channel number of primery channel + * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width) + * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection) */ -struct ieee80211_hw_mode { - struct list_head list; - struct ieee80211_channel *channels; - struct ieee80211_rate *rates; - enum ieee80211_phymode mode; - int num_channels; - int num_rates; +struct ieee80211_ht_bss_info { + u8 primary_channel; + u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */ + u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ }; /** @@ -208,6 +133,7 @@ struct ieee80211_tx_queue_stats_data { * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be * sent after a beacon * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames + * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU */ enum ieee80211_tx_queue { IEEE80211_TX_QUEUE_DATA0, @@ -223,11 +149,12 @@ enum ieee80211_tx_queue { * this struct need to have fixed values. As soon as it is removed, we can * fix these entries. */ IEEE80211_TX_QUEUE_AFTER_BEACON = 6, - IEEE80211_TX_QUEUE_BEACON = 7 + IEEE80211_TX_QUEUE_BEACON = 7, + NUM_TX_DATA_QUEUES_AMPDU = 16 }; struct ieee80211_tx_queue_stats { - struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES]; + struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU]; }; struct ieee80211_low_level_stats { @@ -237,16 +164,56 @@ struct ieee80211_low_level_stats { unsigned int dot11RTSSuccessCount; }; +/** + * enum ieee80211_bss_change - BSS change notification flags + * + * These flags are used with the bss_info_changed() callback + * to indicate which BSS parameter changed. + * + * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), + * also implies a change in the AID. + * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed + * @BSS_CHANGED_ERP_PREAMBLE: preamble changed + */ +enum ieee80211_bss_change { + BSS_CHANGED_ASSOC = 1<<0, + BSS_CHANGED_ERP_CTS_PROT = 1<<1, + BSS_CHANGED_ERP_PREAMBLE = 1<<2, +}; + +/** + * struct ieee80211_bss_conf - holds the BSS's changing parameters + * + * This structure keeps information about a BSS (and an association + * to that BSS) that can change during the lifetime of the BSS. + * + * @assoc: association status + * @aid: association ID number, valid only when @assoc is true + * @use_cts_prot: use CTS protection + * @use_short_preamble: use 802.11b short preamble + */ +struct ieee80211_bss_conf { + /* association related data */ + bool assoc; + u16 aid; + /* erp related data */ + bool use_cts_prot; + bool use_short_preamble; +}; + /* Transmit control fields. This data structure is passed to low-level driver * with each TX frame. The low-level driver is responsible for configuring * the hardware to use given values (depending on what is supported). */ struct ieee80211_tx_control { - int tx_rate; /* Transmit rate, given as the hw specific value for the - * rate (from struct ieee80211_rate) */ - int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw - * specific value for the rate (from - * struct ieee80211_rate) */ + struct ieee80211_vif *vif; + struct ieee80211_rate *tx_rate; + + /* Transmit rate for RTS/CTS frame */ + struct ieee80211_rate *rts_cts_rate; + + /* retry rate for the last retries */ + struct ieee80211_rate *alt_retry_rate; #define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for * this frame */ @@ -265,10 +232,16 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_REQUEUE (1<<7) #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of * the frame */ +#define IEEE80211_TXCTL_SHORT_PREAMBLE (1<<9) #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send * using the through * set_retry_limit configured * long retry value */ +#define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */ +#define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM + * beacon */ +#define IEEE80211_TXCTL_AMPDU (1<<13) /* this frame should be sent + * as part of an A-MPDU */ u32 flags; /* tx control flags defined * above */ u8 key_idx; /* keyidx from hw->set_key(), undefined if @@ -276,22 +249,12 @@ struct ieee80211_tx_control { u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. * This could be used when set_retry_limit * is not implemented by the driver */ - u8 power_level; /* per-packet transmit power level, in dBm */ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ u8 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ - struct ieee80211_rate *rate; /* internal 80211.o rate */ - struct ieee80211_rate *rts_rate; /* internal 80211.o rate - * for RTS/CTS */ - int alt_retry_rate; /* retry rate for the last retries, given as the - * hw specific value for the rate (from - * struct ieee80211_rate). To be used to limit - * packet dropping when probing higher rates, if hw - * supports multiple retry rates. -1 = not used */ int type; /* internal */ - int ifindex; /* internal */ }; @@ -312,6 +275,8 @@ struct ieee80211_tx_control { * the frame. * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on * the frame. + * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field) + * is valid. */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -321,6 +286,7 @@ enum mac80211_rx_flags { RX_FLAG_IV_STRIPPED = 1<<4, RX_FLAG_FAILED_FCS_CRC = 1<<5, RX_FLAG_FAILED_PLCP_CRC = 1<<6, + RX_FLAG_TSFT = 1<<7, }; /** @@ -330,26 +296,24 @@ enum mac80211_rx_flags { * supported by hardware) to the 802.11 code with each received * frame. * @mactime: MAC timestamp as defined by 802.11 + * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz - * @channel: channel the radio was tuned to - * @phymode: active PHY mode * @ssi: signal strength when receiving this frame * @signal: used as 'qual' in statistics reporting * @noise: PHY noise when receiving this frame * @antenna: antenna used - * @rate: data rate + * @rate_idx: index of data rate into band's supported rates * @flag: %RX_FLAG_* */ struct ieee80211_rx_status { u64 mactime; + enum ieee80211_band band; int freq; - int channel; - enum ieee80211_phymode phymode; int ssi; int signal; int noise; int antenna; - int rate; + int rate_idx; int flag; }; @@ -360,12 +324,14 @@ struct ieee80211_rx_status { * * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted * because the destination STA was in powersave mode. - * * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged + * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. */ enum ieee80211_tx_status_flags { IEEE80211_TX_STATUS_TX_FILTERED = 1<<0, IEEE80211_TX_STATUS_ACK = 1<<1, + IEEE80211_TX_STATUS_AMPDU = 1<<2, }; /** @@ -376,24 +342,25 @@ enum ieee80211_tx_status_flags { * * @control: a copy of the &struct ieee80211_tx_control passed to the driver * in the tx() callback. - * * @flags: transmit status flags, defined above - * - * @ack_signal: signal strength of the ACK frame - * + * @retry_count: number of retries * @excessive_retries: set to 1 if the frame was retried many times * but not acknowledged - * - * @retry_count: number of retries - * + * @ampdu_ack_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ampdu_ack_map: block ack bit map for the aggregation. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ack_signal: signal strength of the ACK frame * @queue_length: ?? REMOVE * @queue_number: ?? REMOVE */ struct ieee80211_tx_status { struct ieee80211_tx_control control; u8 flags; - bool excessive_retries; u8 retry_count; + bool excessive_retries; + u8 ampdu_ack_len; + u64 ampdu_ack_map; int ack_signal; int queue_length; int queue_number; @@ -406,11 +373,12 @@ struct ieee80211_tx_status { * * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) - * + * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported) */ enum ieee80211_conf_flags { - IEEE80211_CONF_SHORT_SLOT_TIME = 1<<0, - IEEE80211_CONF_RADIOTAP = 1<<1, + IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0), + IEEE80211_CONF_RADIOTAP = (1<<1), + IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2), }; /** @@ -420,38 +388,32 @@ enum ieee80211_conf_flags { * * @radio_enabled: when zero, driver is required to switch off the radio. * TODO make a flag - * @channel: IEEE 802.11 channel number - * @freq: frequency in MHz - * @channel_val: hardware specific channel value for the channel - * @phymode: PHY mode to activate (REMOVE) - * @chan: channel to switch to, pointer to the channel information - * @mode: pointer to mode definition - * @regulatory_domain: ?? * @beacon_int: beacon interval (TODO make interface config) * @flags: configuration flags defined above - * @power_level: transmit power limit for current regulatory domain in dBm - * @antenna_max: maximum antenna gain + * @power_level: requested transmit power (in dBm) + * @max_antenna_gain: maximum antenna gain (in dBi) * @antenna_sel_tx: transmit antenna selection, 0: default/diversity, * 1/2: antenna 0/1 * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx + * @ht_conf: describes current self configuration of 802.11n HT capabilies + * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters + * @channel: the channel to tune to */ struct ieee80211_conf { - int channel; /* IEEE 802.11 channel number */ - int freq; /* MHz */ - int channel_val; /* hw specific value for the channel */ - - enum ieee80211_phymode phymode; - struct ieee80211_channel *chan; - struct ieee80211_hw_mode *mode; unsigned int regulatory_domain; int radio_enabled; int beacon_int; u32 flags; - u8 power_level; - u8 antenna_max; + int power_level; + int max_antenna_gain; u8 antenna_sel_tx; u8 antenna_sel_rx; + + struct ieee80211_channel *channel; + + struct ieee80211_ht_info ht_conf; + struct ieee80211_ht_bss_info ht_bss_conf; }; /** @@ -480,13 +442,27 @@ enum ieee80211_if_types { }; /** + * struct ieee80211_vif - per-interface data + * + * Data in this structure is continually present for driver + * use during the life of a virtual interface. + * + * @type: type of this virtual interface + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). + */ +struct ieee80211_vif { + enum ieee80211_if_types type; + /* must be last */ + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +/** * struct ieee80211_if_init_conf - initial configuration of an interface * - * @if_id: internal interface ID. This number has no particular meaning to - * drivers and the only allowed usage is to pass it to - * ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions. - * This field is not valid for monitor interfaces - * (interfaces of %IEEE80211_IF_TYPE_MNTR type). + * @vif: pointer to a driver-use per-interface structure. The pointer + * itself is also used for various functions including + * ieee80211_beacon_get() and ieee80211_get_buffered_bc(). * @type: one of &enum ieee80211_if_types constants. Determines the type of * added/removed interface. * @mac_addr: pointer to MAC address of the interface. This pointer is valid @@ -503,8 +479,8 @@ enum ieee80211_if_types { * in pure monitor mode. */ struct ieee80211_if_init_conf { - int if_id; enum ieee80211_if_types type; + struct ieee80211_vif *vif; void *mac_addr; }; @@ -597,9 +573,6 @@ struct ieee80211_key_conf { u8 key[0]; }; -#define IEEE80211_SEQ_COUNTER_RX 0 -#define IEEE80211_SEQ_COUNTER_TX 1 - /** * enum set_key_cmd - key command * @@ -659,15 +632,19 @@ enum sta_notify_cmd { * %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because * otherwise the stack will not know when the DTIM beacon was sent. * - * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED: - * Channels are already configured to the default regulatory domain - * specified in the device's EEPROM + * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: + * Hardware is not capable of short slot operation on the 2.4 GHz band. + * + * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: + * Hardware is not capable of receiving frames with short preamble on + * the 2.4 GHz band. */ enum ieee80211_hw_flags { IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, - IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED = 1<<3, + IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, + IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, }; /** @@ -679,7 +656,8 @@ enum ieee80211_hw_flags { * @wiphy: This points to the &struct wiphy allocated for this * 802.11 PHY. You must fill in the @perm_addr and @dev * members of this structure using SET_IEEE80211_DEV() - * and SET_IEEE80211_PERM_ADDR(). + * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported + * bands (with channels, bitrates) are registered here. * * @conf: &struct ieee80211_conf, device configuration, don't use. * @@ -706,15 +684,24 @@ enum ieee80211_hw_flags { * * @queues: number of available hardware transmit queues for * data packets. WMM/QoS requires at least four. + * + * @rate_control_algorithm: rate control algorithm for this hardware. + * If unset (NULL), the default algorithm will be used. Must be + * set before calling ieee80211_register_hw(). + * + * @vif_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_vif. */ struct ieee80211_hw { struct ieee80211_conf conf; struct wiphy *wiphy; struct workqueue_struct *workqueue; + const char *rate_control_algorithm; void *priv; u32 flags; unsigned int extra_tx_headroom; int channel_change_time; + int vif_data_size; u8 queues; s8 max_rssi; s8 max_signal; @@ -854,19 +841,22 @@ enum ieee80211_filter_flags { }; /** - * enum ieee80211_erp_change_flags - erp change flags - * - * These flags are used with the erp_ie_changed() callback in - * &struct ieee80211_ops to indicate which parameter(s) changed. - * @IEEE80211_ERP_CHANGE_PROTECTION: protection changed - * @IEEE80211_ERP_CHANGE_PREAMBLE: barker preamble mode changed + * enum ieee80211_ampdu_mlme_action - A-MPDU actions + * + * These flags are used with the ampdu_action() callback in + * &struct ieee80211_ops to indicate which action is needed. + * @IEEE80211_AMPDU_RX_START: start Rx aggregation + * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation + * @IEEE80211_AMPDU_TX_START: start Tx aggregation + * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation */ -enum ieee80211_erp_change_flags { - IEEE80211_ERP_CHANGE_PROTECTION = 1<<0, - IEEE80211_ERP_CHANGE_PREAMBLE = 1<<1, +enum ieee80211_ampdu_mlme_action { + IEEE80211_AMPDU_RX_START, + IEEE80211_AMPDU_RX_STOP, + IEEE80211_AMPDU_TX_START, + IEEE80211_AMPDU_TX_STOP, }; - /** * struct ieee80211_ops - callbacks from mac80211 to the driver * @@ -922,6 +912,14 @@ enum ieee80211_erp_change_flags { * @config_interface: Handler for configuration requests related to interfaces * (e.g. BSSID changes.) * + * @bss_info_changed: Handler for configuration requests related to BSS + * parameters that may vary during BSS's lifespan, and may affect low + * level driver (e.g. assoc/disassoc status, erp parameters). + * This function should not be used if no BSS has been set, unless + * for association indication. The @changed parameter indicates which + * of the bss parameters has changed when a call is made. This callback + * has to be atomic. + * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. * This callback must be implemented and atomic. @@ -936,30 +934,16 @@ enum ieee80211_erp_change_flags { * and remove_interface calls, i.e. while the interface with the * given local_address is enabled. * - * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card - * to pass unencrypted EAPOL-Key frames even when encryption is - * configured. If the wlan card does not require such a configuration, - * this function pointer can be set to NULL. - * - * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be - * authorized (@authorized=1) or unauthorized (=0). This function can be - * used if the wlan hardware or low-level driver implements PAE. - * mac80211 will filter frames based on authorization state in any case, - * so this function pointer can be NULL if low-level driver does not - * require event notification about port state changes. - * * @hw_scan: Ask the hardware to service the scan request, no need to start - * the scan state machine in stack. + * the scan state machine in stack. The scan must honour the channel + * configuration done by the regulatory agent in the wiphy's registered + * bands. * * @get_stats: return low-level statistics * - * @set_privacy_invoked: For devices that generate their own beacons and probe - * response or association responses this updates the state of privacy_invoked - * returns 0 for success or an error number. - * - * @get_sequence_counter: For devices that have internal sequence counters this - * callback allows mac80211 to access the current value of a counter. - * This callback seems not well-defined, tell us if you need it. + * @get_tkip_seq: If your device implements TKIP encryption in hardware this + * callback should be provided to read the TKIP transmit IVs (both IV32 + * and IV16) for the given key from hardware. * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) * @@ -972,8 +956,6 @@ enum ieee80211_erp_change_flags { * @sta_notify: Notifies low level driver about addition or removal * of assocaited station or AP. * - * @erp_ie_changed: Handle ERP IE change notifications. Must be atomic. - * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. The @queue parameter uses the * %IEEE80211_TX_QUEUE_* constants. Must be atomic. @@ -1008,6 +990,15 @@ enum ieee80211_erp_change_flags { * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. * This is needed only for IBSS mode and the result of this function is * used to determine whether to reply to Probe Requests. + * + * @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic. + * + * @ampdu_action: Perform a certain A-MPDU action + * The RA/TID combination determines the destination and TID we want + * the ampdu action to be performed for. The action is defined through + * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) + * is the first frame we expect to perform the action on. notice + * that TX/RX_STOP can pass NULL for this parameter. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -1020,7 +1011,12 @@ struct ieee80211_ops { struct ieee80211_if_init_conf *conf); int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int (*config_interface)(struct ieee80211_hw *hw, - int if_id, struct ieee80211_if_conf *conf); + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf); + void (*bss_info_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed); void (*configure_filter)(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -1029,25 +1025,17 @@ struct ieee80211_ops { int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); - int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x); - int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr, - int authorized); int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); int (*get_stats)(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); - int (*set_privacy_invoked)(struct ieee80211_hw *hw, - int privacy_invoked); - int (*get_sequence_counter)(struct ieee80211_hw *hw, - u8* addr, u8 keyidx, u8 txrx, - u32* iv32, u16* iv16); + void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16); int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_retry_limit)(struct ieee80211_hw *hw, u32 short_retry, u32 long_retr); - void (*sta_notify)(struct ieee80211_hw *hw, int if_id, + void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, const u8 *addr); - void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes, - int cts_protection, int preamble); int (*conf_tx)(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params); int (*get_tx_stats)(struct ieee80211_hw *hw, @@ -1058,6 +1046,10 @@ struct ieee80211_ops { struct sk_buff *skb, struct ieee80211_tx_control *control); int (*tx_last_beacon)(struct ieee80211_hw *hw); + int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + int (*ampdu_action)(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn); }; /** @@ -1089,6 +1081,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw); extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); #endif /** * ieee80211_get_tx_led_name - get name of TX LED @@ -1128,6 +1121,16 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) #endif } +/** + * ieee80211_get_assoc_led_name - get name of association LED + * + * mac80211 creates a association LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) { #ifdef CONFIG_MAC80211_LEDS @@ -1137,10 +1140,24 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) #endif } - -/* Register a new hardware PHYMODE capability to the stack. */ -int ieee80211_register_hwmode(struct ieee80211_hw *hw, - struct ieee80211_hw_mode *mode); +/** + * ieee80211_get_radio_led_name - get name of radio LED + * + * mac80211 creates a radio change LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_radio_led_name(hw); +#else + return NULL; +#endif +} /** * ieee80211_unregister_hw - Unregister a hardware device @@ -1226,7 +1243,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, /** * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @control: will be filled with information needed to send this beacon. * * If the beacon frames are generated by the host system (i.e., not in @@ -1237,13 +1254,13 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, * is responsible of freeing it. */ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - int if_id, + struct ieee80211_vif *vif, struct ieee80211_tx_control *control); /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -1254,7 +1271,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * the next RTS frame from the 802.11 code. The low-level is responsible * for calling this function before and RTS frame is needed. */ -void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, +void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts); @@ -1262,7 +1279,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, /** * ieee80211_rts_duration - Get the duration field for an RTS frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -1270,14 +1287,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, - size_t frame_len, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -1288,7 +1305,8 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, * the next CTS-to-self frame from the 802.11 code. The low-level is responsible * for calling this function before and CTS-to-self frame is needed. */ -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts); @@ -1296,7 +1314,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, /** * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -1304,28 +1322,30 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame. - * @rate: the rate (in 100kbps) at which the frame is going to be transmitted. + * @rate: the rate at which the frame is going to be transmitted. * * Calculate the duration field of some generic frame, given its * length and transmission rate (in 100kbps). */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, - int rate); + struct ieee80211_rate *rate); /** * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @control: will be filled with information needed to send returned frame. * * Function for accessing buffered broadcast and multicast frames. If @@ -1344,7 +1364,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, * use common code for all beacons. */ struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_tx_control *control); /** @@ -1422,8 +1442,96 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); */ void ieee80211_scan_completed(struct ieee80211_hw *hw); -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ - ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] +/** + * ieee80211_iterate_active_interfaces - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call, cannot sleep + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data); + +/** + * ieee80211_start_tx_ba_session - Start a tx Block Ack session. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient + * @tid: the TID to BA on. + * @return: success if addBA request was sent, failure otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to start aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); + +/** + * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. + */ +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); + +/** + * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. + * This version of the function is irq safe. + */ +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, + u16 tid); + +/** + * ieee80211_stop_tx_ba_session - Stop a Block Ack session. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient + * @tid: the TID to stop BA. + * @initiator: if indicates initiator DELBA frame will be sent. + * @return: error if no sta with matching da found, success otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to stop aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator); + +/** + * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. + */ +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); + +/** + * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. + * This version of the function is irq safe. + */ +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, + u16 tid); #endif /* MAC80211_H */ diff --git a/package/mac80211/src/include/net/wireless.h b/package/mac80211/src/include/net/wireless.h new file mode 100644 index 0000000000..c7f805ee55 --- /dev/null +++ b/package/mac80211/src/include/net/wireless.h @@ -0,0 +1,307 @@ +#ifndef __NET_WIRELESS_H +#define __NET_WIRELESS_H + +/* + * 802.11 device management + * + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + */ + +#include <linux/netdevice.h> +#include <linux/debugfs.h> +#include <linux/list.h> +#include <net/cfg80211.h> + +/** + * enum ieee80211_band - supported frequency bands + * + * The bands are assigned this way because the supported + * bitrates differ in these bands. + * + * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band + * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) + */ +enum ieee80211_band { + IEEE80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ, + + /* keep last */ + IEEE80211_NUM_BANDS +}; + +/** + * enum ieee80211_channel_flags - channel flags + * + * Channel flags set by the regulatory control code. + * + * @IEEE80211_CHAN_DISABLED: This channel is disabled. + * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted + * on this channel. + * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + */ +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1<<0, + IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_RADAR = 1<<3, +}; + +/** + * struct ieee80211_channel - channel definition + * + * This structure describes a single channel for use + * with cfg80211. + * + * @center_freq: center frequency in MHz + * @hw_value: hardware-specific value for the channel + * @flags: channel flags from &enum ieee80211_channel_flags. + * @orig_flags: channel flags at registration time, used by regulatory + * code to support devices with additional restrictions + * @band: band this channel belongs to. + * @max_antenna_gain: maximum antenna gain in dBi + * @max_power: maximum transmission power (in dBm) + * @orig_mag: internal use + * @orig_mpwr: internal use + */ +struct ieee80211_channel { + enum ieee80211_band band; + u16 center_freq; + u16 hw_value; + u32 flags; + int max_antenna_gain; + int max_power; + u32 orig_flags; + int orig_mag, orig_mpwr; +}; + +/** + * enum ieee80211_rate_flags - rate flags + * + * Hardware/specification flags for rates. These are structured + * in a way that allows using the same bitrate structure for + * different bands/PHY modes. + * + * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short + * preamble on this bitrate; only relevant in 2.4GHz band and + * with CCK rates. + * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate + * when used with 802.11a (on the 5 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate + * when used with 802.11b (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate + * when used with 802.11g (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. + */ +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, + IEEE80211_RATE_MANDATORY_A = 1<<1, + IEEE80211_RATE_MANDATORY_B = 1<<2, + IEEE80211_RATE_MANDATORY_G = 1<<3, + IEEE80211_RATE_ERP_G = 1<<4, +}; + +/** + * struct ieee80211_rate - bitrate definition + * + * This structure describes a bitrate that an 802.11 PHY can + * operate with. The two values @hw_value and @hw_value_short + * are only for driver use when pointers to this structure are + * passed around. + * + * @flags: rate-specific flags + * @bitrate: bitrate in units of 100 Kbps + * @hw_value: driver/hardware value for this rate + * @hw_value_short: driver/hardware value for this rate when + * short preamble is used + */ +struct ieee80211_rate { + u32 flags; + u16 bitrate; + u16 hw_value, hw_value_short; +}; + +/** + * struct ieee80211_ht_info - describing STA's HT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11n HT capabilities for an STA. + * + * @ht_supported: is HT supported by STA, 0: no, 1: yes + * @cap: HT capabilities map as described in 802.11n spec + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing + * @supp_mcs_set: Supported MCS set as described in 802.11n spec + */ +struct ieee80211_ht_info { + u16 cap; /* use IEEE80211_HT_CAP_ */ + u8 ht_supported; + u8 ampdu_factor; + u8 ampdu_density; + u8 supp_mcs_set[16]; +}; + +/** + * struct ieee80211_supported_band - frequency band definition + * + * This structure describes a frequency band a wiphy + * is able to operate in. + * + * @channels: Array of channels the hardware can operate in + * in this band. + * @band: the band this structure represents + * @n_channels: Number of channels in @channels + * @bitrates: Array of bitrates the hardware can operate with + * in this band. Must be sorted to give a valid "supported + * rates" IE, i.e. CCK rates first, then OFDM. + * @n_bitrates: Number of bitrates in @bitrates + */ +struct ieee80211_supported_band { + struct ieee80211_channel *channels; + struct ieee80211_rate *bitrates; + enum ieee80211_band band; + int n_channels; + int n_bitrates; + struct ieee80211_ht_info ht_info; +}; + +/** + * struct wiphy - wireless hardware description + * @idx: the wiphy index assigned to this item + * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name> + */ +struct wiphy { + /* assign these fields before you register the wiphy */ + + /* permanent MAC address */ + u8 perm_addr[ETH_ALEN]; + + /* If multiple wiphys are registered and you're handed e.g. + * a regular netdev with assigned ieee80211_ptr, you won't + * know whether it points to a wiphy your driver has registered + * or not. Assign this to something global to your driver to + * help determine whether you own this wiphy or not. */ + void *privid; + + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; + + /* fields below are read-only, assigned by cfg80211 */ + + /* the item in /sys/class/ieee80211/ points to this, + * you need use set_wiphy_dev() (see below) */ + struct device dev; + + /* dir in debugfs: ieee80211/<wiphyname> */ + struct dentry *debugfsdir; + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +/** struct wireless_dev - wireless per-netdev state + * + * This structure must be allocated by the driver/stack + * that uses the ieee80211_ptr field in struct net_device + * (this is intentional so it can be allocated along with + * the netdev.) + * + * @wiphy: pointer to hardware description + */ +struct wireless_dev { + struct wiphy *wiphy; + + /* private to the generic wireless code */ + struct list_head list; + struct net_device *netdev; +}; + +/** + * wiphy_priv - return priv from wiphy + */ +static inline void *wiphy_priv(struct wiphy *wiphy) +{ + BUG_ON(!wiphy); + return &wiphy->priv; +} + +/** + * set_wiphy_dev - set device pointer for wiphy + */ +static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) +{ + wiphy->dev.parent = dev; +} + +/** + * wiphy_dev - get wiphy dev pointer + */ +static inline struct device *wiphy_dev(struct wiphy *wiphy) +{ + return wiphy->dev.parent; +} + +/** + * wiphy_name - get wiphy name + */ +static inline char *wiphy_name(struct wiphy *wiphy) +{ + return wiphy->dev.bus_id; +} + +/** + * wdev_priv - return wiphy priv from wireless_dev + */ +static inline void *wdev_priv(struct wireless_dev *wdev) +{ + BUG_ON(!wdev); + return wiphy_priv(wdev->wiphy); +} + +/** + * wiphy_new - create a new wiphy for use with cfg80211 + * + * create a new wiphy and associate the given operations with it. + * @sizeof_priv bytes are allocated for private use. + * + * the returned pointer must be assigned to each netdev's + * ieee80211_ptr for proper operation. + */ +struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv); + +/** + * wiphy_register - register a wiphy with cfg80211 + * + * register the given wiphy + * + * Returns a non-negative wiphy index or a negative error code. + */ +extern int wiphy_register(struct wiphy *wiphy); + +/** + * wiphy_unregister - deregister a wiphy from cfg80211 + * + * unregister a device with the given priv pointer. + * After this call, no more requests can be made with this priv + * pointer, but the call may sleep to wait for an outstanding + * request that is being handled. + */ +extern void wiphy_unregister(struct wiphy *wiphy); + +/** + * wiphy_free - free wiphy + */ +extern void wiphy_free(struct wiphy *wiphy); + +/** + * ieee80211_channel_to_frequency - convert channel number to frequency + */ +extern int ieee80211_channel_to_frequency(int chan); + +/** + * ieee80211_frequency_to_channel - convert frequency to channel number + */ +extern int ieee80211_frequency_to_channel(int freq); + +#endif /* __NET_WIRELESS_H */ diff --git a/package/mac80211/src/net/mac80211/Kconfig b/package/mac80211/src/net/mac80211/Kconfig index 6fffb3845a..45c7c0c387 100644 --- a/package/mac80211/src/net/mac80211/Kconfig +++ b/package/mac80211/src/net/mac80211/Kconfig @@ -1,6 +1,5 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" - depends on EXPERIMENTAL select CRYPTO select CRYPTO_ECB select CRYPTO_ARC4 @@ -10,15 +9,84 @@ config MAC80211 select CFG80211 select NET_SCH_FIFO ---help--- - This option enables the hardware independent IEEE 802.11 - networking stack. + This option enables the hardware independent IEEE 802.11 + networking stack. + +menu "Rate control algorithm selection" + depends on MAC80211 != n + +choice + prompt "Default rate control algorithm" + default MAC80211_RC_DEFAULT_PID + ---help--- + This option selects the default rate control algorithm + mac80211 will use. Note that this default can still be + overriden through the ieee80211_default_rc_algo module + parameter if different algorithms are available. + +config MAC80211_RC_DEFAULT_PID + bool "PID controller based rate control algorithm" + select MAC80211_RC_PID + ---help--- + Select the PID controller based rate control as the + default rate control algorithm. You should choose + this unless you know what you are doing. + +config MAC80211_RC_DEFAULT_SIMPLE + bool "Simple rate control algorithm" + select MAC80211_RC_SIMPLE + ---help--- + Select the simple rate control as the default rate + control algorithm. Note that this is a non-responsive, + dumb algorithm. You should choose the PID rate control + instead. + +config MAC80211_RC_DEFAULT_NONE + bool "No default algorithm" + depends on EMBEDDED + help + Selecting this option will select no default algorithm + and allow you to not build any. Do not choose this + option unless you know your driver comes with another + suitable algorithm. +endchoice + +comment "Selecting 'y' for an algorithm will" +comment "build the algorithm into mac80211." + +config MAC80211_RC_DEFAULT + string + default "pid" if MAC80211_RC_DEFAULT_PID + default "simple" if MAC80211_RC_DEFAULT_SIMPLE + default "" + +config MAC80211_RC_PID + tristate "PID controller based rate control algorithm" + ---help--- + This option enables a TX rate control algorithm for + mac80211 that uses a PID controller to select the TX + rate. + + Say Y or M unless you're sure you want to use a + different rate control algorithm. + +config MAC80211_RC_SIMPLE + tristate "Simple rate control algorithm (DEPRECATED)" + ---help--- + This option enables a very simple, non-responsive TX + rate control algorithm. This algorithm is deprecated + and will be removed from the kernel in the near future. + It has been replaced by the PID algorithm. + + Say N unless you know what you are doing. +endmenu config MAC80211_LEDS bool "Enable LED triggers" depends on MAC80211 && LEDS_TRIGGERS ---help--- - This option enables a few LED triggers for different - packet receive/transmit events. + This option enables a few LED triggers for different + packet receive/transmit events. config MAC80211_DEBUGFS bool "Export mac80211 internals in DebugFS" @@ -29,6 +97,18 @@ config MAC80211_DEBUGFS Say N unless you know you need this. +config MAC80211_DEBUG_PACKET_ALIGNMENT + bool "Enable packet alignment debugging" + depends on MAC80211 + help + This option is recommended for driver authors and strongly + discouraged for everybody else, it will trigger a warning + when a driver hands mac80211 a buffer that is aligned in + a way that will cause problems with the IP stack on some + architectures. + + Say N unless you're writing a mac80211 based driver. + config MAC80211_DEBUG bool "Enable debugging output" depends on MAC80211 @@ -39,6 +119,16 @@ config MAC80211_DEBUG If you are not trying to debug or develop the ieee80211 subsystem, you most likely want to say N here. +config MAC80211_HT_DEBUG + bool "Enable HT debugging output" + depends on MAC80211_DEBUG + ---help--- + This option enables 802.11n High Throughput features + debug tracing output. + + If you are not trying to debug of develop the ieee80211 + subsystem, you most likely want to say N here. + config MAC80211_VERBOSE_DEBUG bool "Verbose debugging output" depends on MAC80211_DEBUG diff --git a/package/mac80211/src/net/mac80211/Makefile b/package/mac80211/src/net/mac80211/Makefile index 219cd9f934..9d7a19581a 100644 --- a/package/mac80211/src/net/mac80211/Makefile +++ b/package/mac80211/src/net/mac80211/Makefile @@ -1,10 +1,15 @@ -obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o +obj-$(CONFIG_MAC80211) += mac80211.o -mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o -mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o -mac80211-objs-$(CONFIG_NET_SCHED) += wme.o +# objects for PID algorithm +rc80211_pid-y := rc80211_pid_algo.o +rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o -mac80211-objs := \ +# build helper for PID algorithm +rc-pid-y := $(rc80211_pid-y) +rc-pid-m := rc80211_pid.o + +# mac80211 objects +mac80211-y := \ ieee80211.o \ ieee80211_ioctl.o \ sta_info.o \ @@ -14,7 +19,6 @@ mac80211-objs := \ ieee80211_iface.o \ ieee80211_rate.o \ michael.o \ - regdomain.o \ tkip.o \ aes_ccm.o \ cfg.o \ @@ -22,5 +26,22 @@ mac80211-objs := \ tx.o \ key.o \ util.o \ - event.o \ - $(mac80211-objs-y) + event.o + +mac80211-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o +mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ + debugfs.o \ + debugfs_sta.o \ + debugfs_netdev.o \ + debugfs_key.o + + +# Build rate control algorithm(s) +CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE +CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE +mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o +mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID)) + +# Modular rate algorithms are assigned to mac80211-m - make separate modules +obj-m += $(mac80211-m) diff --git a/package/mac80211/src/net/mac80211/aes_ccm.c b/package/mac80211/src/net/mac80211/aes_ccm.c index e55569bee7..e62fe55944 100644 --- a/package/mac80211/src/net/mac80211/aes_ccm.c +++ b/package/mac80211/src/net/mac80211/aes_ccm.c @@ -7,10 +7,10 @@ * published by the Free Software Foundation. */ +#include <linux/kernel.h> #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> -#include <asm/scatterlist.h> #include <net/mac80211.h> #include "ieee80211_key.h" @@ -63,7 +63,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, b); @@ -102,7 +102,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, a); diff --git a/package/mac80211/src/net/mac80211/cfg.c b/package/mac80211/src/net/mac80211/cfg.c index cd78b3f29c..a083cc7885 100644 --- a/package/mac80211/src/net/mac80211/cfg.c +++ b/package/mac80211/src/net/mac80211/cfg.c @@ -1,16 +1,20 @@ /* * mac80211 configuration hooks for cfg80211 * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> * * This file is GPLv2 as found in COPYING. */ +#include <linux/ieee80211.h> #include <linux/nl80211.h> #include <linux/rtnetlink.h> +#include <net/net_namespace.h> +#include <linux/rcupdate.h> #include <net/cfg80211.h> #include "ieee80211_i.h" #include "cfg.h" +#include "ieee80211_rate.h" static enum ieee80211_if_types nl80211_type_to_mac80211_type(enum nl80211_iftype type) @@ -30,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) } static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags) { struct ieee80211_local *local = wiphy_priv(wiphy); enum ieee80211_if_types itype; + struct net_device *dev; + struct ieee80211_sub_if_data *sdata; + int err; if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; @@ -42,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - return ieee80211_if_add(local->mdev, name, NULL, itype); + err = ieee80211_if_add(local->mdev, name, &dev, itype); + if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) + return err; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->u.mntr_flags = *flags; + return 0; } static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) @@ -55,7 +68,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) return -ENODEV; /* we're under RTNL */ - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(&init_net, ifindex); if (!dev) return 0; @@ -65,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) } static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags) { struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; @@ -76,7 +89,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, return -ENODEV; /* we're under RTNL */ - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(&init_net, ifindex); if (!dev) return -ENODEV; @@ -89,12 +102,551 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_VLAN) + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) return -EOPNOTSUPP; ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) + return 0; + + sdata->u.mntr_flags = *flags; + return 0; +} + +static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, u8 *mac_addr, + struct key_params *params) +{ + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta = NULL; + enum ieee80211_key_alg alg; + int ret; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + alg = ALG_WEP; + break; + case WLAN_CIPHER_SUITE_TKIP: + alg = ALG_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + alg = ALG_CCMP; + break; + default: + return -EINVAL; + } + + if (mac_addr) { + sta = sta_info_get(sdata->local, mac_addr); + if (!sta) + return -ENOENT; + } + + ret = 0; + if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, + params->key_len, params->key)) + ret = -ENOMEM; + + if (sta) + sta_info_put(sta); + + return ret; +} + +static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, u8 *mac_addr) +{ + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + int ret; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (mac_addr) { + sta = sta_info_get(sdata->local, mac_addr); + if (!sta) + return -ENOENT; + + ret = 0; + if (sta->key) + ieee80211_key_free(sta->key); + else + ret = -ENOENT; + + sta_info_put(sta); + return ret; + } + + if (!sdata->keys[key_idx]) + return -ENOENT; + + ieee80211_key_free(sdata->keys[key_idx]); + + return 0; +} + +static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *params)) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sta_info *sta = NULL; + u8 seq[6] = {0}; + struct key_params params; + struct ieee80211_key *key; + u32 iv32; + u16 iv16; + int err = -ENOENT; + + if (mac_addr) { + sta = sta_info_get(sdata->local, mac_addr); + if (!sta) + goto out; + + key = sta->key; + } else + key = sdata->keys[key_idx]; + + if (!key) + goto out; + + memset(¶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; } @@ -102,4 +654,15 @@ struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, .change_virtual_intf = ieee80211_change_iface, + .add_key = ieee80211_add_key, + .del_key = ieee80211_del_key, + .get_key = ieee80211_get_key, + .set_default_key = ieee80211_config_default_key, + .add_beacon = ieee80211_add_beacon, + .set_beacon = ieee80211_set_beacon, + .del_beacon = ieee80211_del_beacon, + .add_station = ieee80211_add_station, + .del_station = ieee80211_del_station, + .change_station = ieee80211_change_station, + .get_station = ieee80211_get_station, }; diff --git a/package/mac80211/src/net/mac80211/debugfs.c b/package/mac80211/src/net/mac80211/debugfs.c index 60514b2c97..4736c64937 100644 --- a/package/mac80211/src/net/mac80211/debugfs.c +++ b/package/mac80211/src/net/mac80211/debugfs.c @@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file) return 0; } -static const char *ieee80211_mode_str(int mode) -{ - switch (mode) { - case MODE_IEEE80211A: - return "IEEE 802.11a"; - case MODE_IEEE80211B: - return "IEEE 802.11b"; - case MODE_IEEE80211G: - return "IEEE 802.11g"; - default: - return "UNKNOWN"; - } -} - -static ssize_t modes_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - struct ieee80211_hw_mode *mode; - char buf[150], *p = buf; - - /* FIXME: locking! */ - list_for_each_entry(mode, &local->modes_list, list) { - p += scnprintf(p, sizeof(buf)+buf-p, - "%s\n", ieee80211_mode_str(mode->mode)); - } - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations modes_ops = { - .read = modes_read, - .open = mac80211_open_file_generic, -}; - #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -80,10 +45,8 @@ static const struct file_operations name## _ops = { \ local->debugfs.name = NULL; -DEBUGFS_READONLY_FILE(channel, 20, "%d", - local->hw.conf.channel); DEBUGFS_READONLY_FILE(frequency, 20, "%d", - local->hw.conf.freq); + local->hw.conf.channel->center_freq); DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", local->hw.conf.antenna_sel_tx); DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", @@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", local->long_retry_limit); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); -DEBUGFS_READONLY_FILE(mode, 20, "%s", - ieee80211_mode_str(local->hw.conf.phymode)); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", @@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.stations = debugfs_create_dir("stations", phyd); local->debugfs.keys = debugfs_create_dir("keys", phyd); - DEBUGFS_ADD(channel); DEBUGFS_ADD(frequency); DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); @@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(short_retry_limit); DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(total_ps_buffered); - DEBUGFS_ADD(mode); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(modes); statsd = debugfs_create_dir("statistics", phyd); local->debugfs.statistics = statsd; @@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { - DEBUGFS_DEL(channel); DEBUGFS_DEL(frequency); DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); @@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(short_retry_limit); DEBUGFS_DEL(long_retry_limit); DEBUGFS_DEL(total_ps_buffered); - DEBUGFS_DEL(mode); DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(modes); DEBUGFS_STATS_DEL(transmitted_fragment_count); DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); diff --git a/package/mac80211/src/net/mac80211/debugfs_key.c b/package/mac80211/src/net/mac80211/debugfs_key.c index 8e4a1bcd16..c881524c87 100644 --- a/package/mac80211/src/net/mac80211/debugfs_key.c +++ b/package/mac80211/src/net/mac80211/debugfs_key.c @@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, struct sta_info *sta) { char buf[50]; + DECLARE_MAC_BUF(mac); if (!key->debugfs.dir) return; - sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr)); + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); } diff --git a/package/mac80211/src/net/mac80211/debugfs_netdev.c b/package/mac80211/src/net/mac80211/debugfs_netdev.c index 2b5e7615e5..29f7b98ba1 100644 --- a/package/mac80211/src/net/mac80211/debugfs_netdev.c +++ b/package/mac80211/src/net/mac80211/debugfs_netdev.c @@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ int buflen) \ { \ - return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ + DECLARE_MAC_BUF(mac); \ + return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ } #define __IEEE80211_IF_FILE(name) \ @@ -90,8 +91,6 @@ static const struct file_operations name##_ops = { \ /* common attributes */ IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); -IEEE80211_IF_FILE(eapol, eapol, DEC); -IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC); /* STA/IBSS attributes */ IEEE80211_IF_FILE(state, u.sta.state, DEC); @@ -118,13 +117,12 @@ static ssize_t ieee80211_if_fmt_flags( sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : ""); + sdata->bss_conf.use_cts_prot ? "CTS prot\n" : ""); } __IEEE80211_IF_FILE(flags); /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); -IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC); IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC); @@ -138,26 +136,6 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( } __IEEE80211_IF_FILE(num_buffered_multicast); -static ssize_t ieee80211_if_fmt_beacon_head_len( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - if (sdata->u.ap.beacon_head) - return scnprintf(buf, buflen, "%d\n", - sdata->u.ap.beacon_head_len); - return scnprintf(buf, buflen, "\n"); -} -__IEEE80211_IF_FILE(beacon_head_len); - -static ssize_t ieee80211_if_fmt_beacon_tail_len( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - if (sdata->u.ap.beacon_tail) - return scnprintf(buf, buflen, "%d\n", - sdata->u.ap.beacon_tail_len); - return scnprintf(buf, buflen, "\n"); -} -__IEEE80211_IF_FILE(beacon_tail_len); - /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); @@ -169,8 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(eapol, sta); - DEBUGFS_ADD(ieee8021_x, sta); DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(prev_bssid, sta); @@ -191,25 +167,18 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(drop_unencrypted, ap); - DEBUGFS_ADD(eapol, ap); - DEBUGFS_ADD(ieee8021_x, ap); DEBUGFS_ADD(num_sta_ps, ap); - DEBUGFS_ADD(dtim_period, ap); DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(num_beacons, ap); DEBUGFS_ADD(force_unicast_rateidx, ap); DEBUGFS_ADD(max_ratectrl_rateidx, ap); DEBUGFS_ADD(num_buffered_multicast, ap); - DEBUGFS_ADD(beacon_head_len, ap); - DEBUGFS_ADD(beacon_tail_len, ap); } static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(eapol, wds); - DEBUGFS_ADD(ieee8021_x, wds); DEBUGFS_ADD(peer, wds); } @@ -217,8 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(eapol, vlan); - DEBUGFS_ADD(ieee8021_x, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -230,7 +197,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata) if (!sdata->debugfsdir) return; - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: add_sta_files(sdata); @@ -262,8 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(eapol, sta); - DEBUGFS_DEL(ieee8021_x, sta); DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(prev_bssid, sta); @@ -284,25 +249,18 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(drop_unencrypted, ap); - DEBUGFS_DEL(eapol, ap); - DEBUGFS_DEL(ieee8021_x, ap); DEBUGFS_DEL(num_sta_ps, ap); - DEBUGFS_DEL(dtim_period, ap); DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(num_beacons, ap); DEBUGFS_DEL(force_unicast_rateidx, ap); DEBUGFS_DEL(max_ratectrl_rateidx, ap); DEBUGFS_DEL(num_buffered_multicast, ap); - DEBUGFS_DEL(beacon_head_len, ap); - DEBUGFS_DEL(beacon_tail_len, ap); } static void del_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(eapol, wds); - DEBUGFS_DEL(ieee8021_x, wds); DEBUGFS_DEL(peer, wds); } @@ -310,8 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(eapol, vlan); - DEBUGFS_DEL(ieee8021_x, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -361,7 +317,7 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) { - del_files(sdata, sdata->type); + del_files(sdata, sdata->vif.type); debugfs_remove(sdata->debugfsdir); sdata->debugfsdir = NULL; } diff --git a/package/mac80211/src/net/mac80211/debugfs_sta.c b/package/mac80211/src/net/mac80211/debugfs_sta.c index 4ea0ea7ea0..ac61353ae7 100644 --- a/package/mac80211/src/net/mac80211/debugfs_sta.c +++ b/package/mac80211/src/net/mac80211/debugfs_sta.c @@ -33,25 +33,16 @@ static ssize_t sta_ ##name## _read(struct file *file, \ #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n") #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") -#define STA_READ_RATE(name, field) \ -static ssize_t sta_##name##_read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct sta_info *sta = file->private_data; \ - struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\ - struct ieee80211_hw_mode *mode = local->oper_hw_mode; \ - char buf[20]; \ - int res = scnprintf(buf, sizeof(buf), "%d\n", \ - (sta->field >= 0 && \ - sta->field < mode->num_rates) ? \ - mode->rates[sta->field].rate : -1); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +#define STA_OPS(name) \ +static const struct file_operations sta_ ##name## _ops = { \ + .read = sta_##name##_read, \ + .open = mac80211_open_file_generic, \ } -#define STA_OPS(name) \ +#define STA_OPS_WR(name) \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ + .write = sta_##name##_write, \ .open = mac80211_open_file_generic, \ } @@ -70,8 +61,6 @@ STA_FILE(rx_fragments, rx_fragments, LU); STA_FILE(rx_dropped, rx_dropped, LU); STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); -STA_FILE(txrate, txrate, RATE); -STA_FILE(last_txrate, last_txrate, RATE); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_rssi, last_rssi, D); @@ -85,12 +74,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", sta->flags & WLAN_STA_PS ? "PS\n" : "", sta->flags & WLAN_STA_TIM ? "TIM\n" : "", - sta->flags & WLAN_STA_PERM ? "PERM\n" : "", sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", sta->flags & WLAN_STA_WME ? "WME\n" : "", @@ -191,6 +179,113 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, STA_OPS(wme_tx_queue); #endif +static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[768], *p = buf; + int i; + struct sta_info *sta = file->private_data; + p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n"); + p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n " + "TIDs info is: \n TID :", + (sta->ampdu_mlme.dialog_token_allocator + 1)); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].ssn); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + + return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); +} + +static ssize_t sta_agg_status_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct net_device *dev = sta->dev; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + u8 *da = sta->addr; + static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1}; + char *endp; + char buf[32]; + int buf_size, rs; + unsigned int tid_num; + char state[4]; + + memset(buf, 0x00, sizeof(buf)); + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + tid_num = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + + if ((tid_num >= 100) && (tid_num <= 115)) { + /* toggle Rx aggregation command */ + tid_num = tid_num - 100; + if (tid_static_rx[tid_num] == 1) { + strcpy(state, "off "); + ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, + WLAN_REASON_QSTA_REQUIRE_SETUP); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF; + tid_static_rx[tid_num] = 0; + } else { + strcpy(state, "on "); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00; + tid_static_rx[tid_num] = 1; + } + printk(KERN_DEBUG "debugfs - try switching tid %u %s\n", + tid_num, state); + } else if ((tid_num >= 0) && (tid_num <= 15)) { + /* toggle Tx aggregation command */ + if (tid_static_tx[tid_num] == 0) { + strcpy(state, "on "); + rs = ieee80211_start_tx_ba_session(hw, da, tid_num); + if (rs == 0) + tid_static_tx[tid_num] = 1; + } else { + strcpy(state, "off"); + rs = ieee80211_stop_tx_ba_session(hw, da, tid_num, 1); + if (rs == 0) + tid_static_tx[tid_num] = 0; + } + printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n", + tid_num, state, rs); + } + + return count; +} +STA_OPS_WR(agg_status); + #define DEBUGFS_ADD(name) \ sta->debugfs.name = debugfs_create_file(#name, 0444, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -202,15 +297,15 @@ STA_OPS(wme_tx_queue); void ieee80211_sta_debugfs_add(struct sta_info *sta) { - char buf[3*6]; struct dentry *stations_dir = sta->local->debugfs.stations; + DECLARE_MAC_BUF(mac); if (!stations_dir) return; - sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); + print_mac(mac, sta->addr); - sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); + sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) return; @@ -224,6 +319,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(wme_rx_queue); DEBUGFS_ADD(wme_tx_queue); #endif + DEBUGFS_ADD(agg_status); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) @@ -238,6 +334,7 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(wme_rx_queue); DEBUGFS_DEL(wme_tx_queue); #endif + DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); sta->debugfs.dir = NULL; diff --git a/package/mac80211/src/net/mac80211/event.c b/package/mac80211/src/net/mac80211/event.c index 68a526cb76..2280f40b45 100644 --- a/package/mac80211/src/net/mac80211/event.c +++ b/package/mac80211/src/net/mac80211/event.c @@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); + DECLARE_MAC_BUF(mac); if (buf) { /* TODO: needed parameters: count, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", + "keyid=%d %scast addr=%s)", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); diff --git a/package/mac80211/src/net/mac80211/ieee80211.c b/package/mac80211/src/net/mac80211/ieee80211.c index 64fa7204b4..1a0171d2f1 100644 --- a/package/mac80211/src/net/mac80211/ieee80211.c +++ b/package/mac80211/src/net/mac80211/ieee80211.c @@ -21,6 +21,7 @@ #include <linux/wireless.h> #include <linux/rtnetlink.h> #include <linux/bitmap.h> +#include <net/net_namespace.h> #include <net/cfg80211.h> #include "ieee80211_i.h" @@ -33,6 +34,8 @@ #include "debugfs.h" #include "debugfs_netdev.h" +#define SUPP_MCS_SET_LEN 16 + /* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. @@ -45,7 +48,7 @@ struct ieee80211_tx_status_rtap_hdr { /* common interface routines */ -static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) +static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; @@ -64,9 +67,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local) new_flags |= FIF_ALLMULTI; if (local->monitors) - new_flags |= FIF_CONTROL | - FIF_OTHER_BSS | - FIF_BCN_PRBRESP_PROMISC; + new_flags |= FIF_BCN_PRBRESP_PROMISC; + + if (local->fif_fcsfail) + new_flags |= FIF_FCSFAIL; + + if (local->fif_plcpfail) + new_flags |= FIF_PLCPFAIL; + + if (local->fif_control) + new_flags |= FIF_CONTROL; + + if (local->fif_other_bss) + new_flags |= FIF_OTHER_BSS; changed_flags = local->filter_flags ^ new_flags; @@ -174,21 +187,21 @@ static int ieee80211_open(struct net_device *dev) /* * check whether it may have the same address */ - if (!identical_mac_addr_allowed(sdata->type, - nsdata->type)) + if (!identical_mac_addr_allowed(sdata->vif.type, + nsdata->vif.type)) return -ENOTUNIQ; /* * can only add VLANs to enabled APs */ - if (sdata->type == IEEE80211_IF_TYPE_VLAN && - nsdata->type == IEEE80211_IF_TYPE_AP && + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && + nsdata->vif.type == IEEE80211_IF_TYPE_AP && netif_running(nsdata->dev)) sdata->u.vlan.ap = nsdata; } } - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_WDS: if (is_zero_ether_addr(sdata->u.wds.remote_addr)) return -ENOLINK; @@ -215,32 +228,46 @@ static int ieee80211_open(struct net_device *dev) res = local->ops->start(local_to_hw(local)); if (res) return res; + ieee80211_hw_config(local); + ieee80211_led_radio(local, local->hw.conf.radio_enabled); } - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_VLAN: list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs++; + break; + } + /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - + if (local->monitors == 1) local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - ieee80211_hw_config(local); - } + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control++; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss++; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; /* fall through */ default: - conf.if_id = dev->ifindex; - conf.type = sdata->type; + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; res = local->ops->add_interface(local_to_hw(local), &conf); if (res && !local->open_count && local->ops->stop) @@ -252,7 +279,7 @@ static int ieee80211_open(struct net_device *dev) ieee80211_reset_erp_info(dev); ieee80211_enable_keys(sdata); - if (sdata->type == IEEE80211_IF_TYPE_STA && + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) netif_carrier_off(dev); else @@ -266,6 +293,17 @@ static int ieee80211_open(struct net_device *dev) tasklet_enable(&local->tasklet); } + /* + * set_multicast_list will be invoked by the networking core + * which will check whether any increments here were done in + * error and sync them down to the hardware as filter flags. + */ + if (sdata->flags & IEEE80211_SDATA_ALLMULTI) + atomic_inc(&local->iff_allmultis); + + if (sdata->flags & IEEE80211_SDATA_PROMISC) + atomic_inc(&local->iff_promiscs); + local->open_count++; netif_start_queue(dev); @@ -278,17 +316,47 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_init_conf conf; + struct sta_info *sta; + int i; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + list_for_each_entry(sta, &local->sta_list, list) { + if (sta->dev == dev) + for (i = 0; i < STA_TID_NUM; i++) + ieee80211_sta_stop_rx_ba_session(sta->dev, + sta->addr, i, + WLAN_BACK_RECIPIENT, + WLAN_REASON_QSTA_LEAVE_QBSS); + } + netif_stop_queue(dev); + /* + * Don't count this interface for promisc/allmulti while it + * is down. dev_mc_unsync() will invoke set_multicast_list + * on the master interface which will sync these down to the + * hardware as filter flags. + */ + if (sdata->flags & IEEE80211_SDATA_ALLMULTI) + atomic_dec(&local->iff_allmultis); + + if (sdata->flags & IEEE80211_SDATA_PROMISC) + atomic_dec(&local->iff_promiscs); + dev_mc_unsync(local->mdev, dev); - /* down all dependent devices, that is VLANs */ - if (sdata->type == IEEE80211_IF_TYPE_AP) { + /* APs need special treatment */ + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { struct ieee80211_sub_if_data *vlan, *tmp; + struct beacon_data *old_beacon = sdata->u.ap.beacon; + + /* remove beacon */ + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(old_beacon); + /* down all dependent devices, that is VLANs */ list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, u.vlan.list) dev_close(vlan->dev); @@ -297,22 +365,34 @@ static int ieee80211_stop(struct net_device *dev) local->open_count--; - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_VLAN: list_del(&sdata->u.vlan.list); sdata->u.vlan.ap = NULL; /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: - local->monitors--; - if (local->monitors == 0) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - ieee80211_hw_config(local); + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs--; + break; } + + local->monitors--; + if (local->monitors == 0) + local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control--; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss--; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -327,16 +407,24 @@ static int ieee80211_stop(struct net_device *dev) synchronize_rcu(); skb_queue_purge(&sdata->u.sta.skb_queue); - if (!local->ops->hw_scan && - local->scan_dev == sdata->dev) { - local->sta_scanning = 0; - cancel_delayed_work(&local->scan_work); + if (local->scan_dev == sdata->dev) { + if (!local->ops->hw_scan) { + local->sta_sw_scanning = 0; + cancel_delayed_work(&local->scan_work); + } else + local->sta_hw_scanning = 0; } + flush_workqueue(local->hw.workqueue); + + sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; + kfree(sdata->u.sta.extra_ie); + sdata->u.sta.extra_ie = NULL; + sdata->u.sta.extra_ie_len = 0; /* fall through */ default: - conf.if_id = dev->ifindex; - conf.type = sdata->type; + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); @@ -350,6 +438,8 @@ static int ieee80211_stop(struct net_device *dev) if (local->ops->stop) local->ops->stop(local_to_hw(local)); + ieee80211_led_radio(local, 0); + tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } @@ -357,6 +447,329 @@ static int ieee80211_stop(struct net_device *dev) return 0; } +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata; + u16 start_seq_num = 0; + u8 *state; + int ret; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find the station\n"); + return -ENOENT; + } + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + /* we have tried too many times, receiver does not want A-MPDU */ + if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) { + ret = -EBUSY; + goto start_ba_exit; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID is not in aggregation flow already */ + if (*state != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - session is not " + "idle on tid %u\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EAGAIN; + goto start_ba_exit; + } + + /* ensure that TX flow won't interrupt us + * until the end of the call to requeue function */ + spin_lock_bh(&local->mdev->queue_lock); + + /* create a new queue for this aggregation */ + ret = ieee80211_ht_agg_queue_add(local, sta, tid); + + /* case no queue is available to aggregation + * don't switch to aggregation */ + if (ret) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - no queue available for" + " tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + goto start_ba_exit; + } + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the + * call back right away, it must see that the flow has begun */ + *state |= HT_ADDBA_REQUESTED_MSK; + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, + ra, tid, &start_seq_num); + + if (ret) { + /* No need to requeue the packets in the agg queue, since we + * held the tx lock: no packet could be enqueued to the newly + * allocated queue */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - HW or queue unavailable" + " for tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + *state = HT_AGG_STATE_IDLE; + goto start_ba_exit; + } + + /* Will put all the packets in the new SW queue */ + ieee80211_requeue(local, ieee802_1d_to_ac[tid]); + spin_unlock_bh(&local->mdev->queue_lock); + + /* We have most probably almost emptied the legacy queue */ + /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */ + + /* send an addBA request */ + sta->ampdu_mlme.dialog_token_allocator++; + sta->ampdu_mlme.tid_tx[tid].dialog_token = + sta->ampdu_mlme.dialog_token_allocator; + sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; + + ieee80211_send_addba_request(sta->dev, ra, tid, + sta->ampdu_mlme.tid_tx[tid].dialog_token, + sta->ampdu_mlme.tid_tx[tid].ssn, + 0x40, 5000); + + /* activate the timer for the recipient's addBA response */ + sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires = + jiffies + ADDBA_RESP_INTERVAL; + add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); + printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); + +start_ba_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_session); + +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int ret = 0; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) + return -ENOENT; + + /* check if the TID is in aggregation */ + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (*state != HT_AGG_STATE_OPERATIONAL) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Try to stop Tx aggregation on" + " non active TID\n"); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -ENOENT; + goto stop_BA_exit; + } + + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); + + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, + ra, tid, NULL); + + /* case HW denied going back to legacy */ + if (ret) { + WARN_ON(ret != -EBUSY); + *state = HT_AGG_STATE_OPERATIONAL; + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + goto stop_BA_exit; + } + +stop_BA_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); + +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", + *state); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return; + } + + WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); + + *state |= HT_ADDBA_DRV_READY_MSK; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); + +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int agg_queue; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", + print_mac(mac, ra), tid); + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { + printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); + sta_info_put(sta); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + return; + } + + if (*state & HT_AGG_STATE_INITIATOR_MSK) + ieee80211_send_delba(sta->dev, ra, tid, + WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); + + agg_queue = sta->tid_to_tx_q[tid]; + + /* avoid ordering issues: we are the only one that can modify + * the content of the qdiscs */ + spin_lock_bh(&local->mdev->queue_lock); + /* remove the queue for this aggregation */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 1); + spin_unlock_bh(&local->mdev->queue_lock); + + /* we just requeued the all the frames that were in the removed + * queue, and since we might miss a softirq we do netif_schedule. + * ieee80211_wake_queue is not used here as this queue is not + * necessarily stopped */ + netif_schedule(local->mdev); + *state = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); + +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping start BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_ADDBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); + +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping stop BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_DELBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); + static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -365,8 +778,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) allmulti = !!(dev->flags & IFF_ALLMULTI); promisc = !!(dev->flags & IFF_PROMISC); - sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; - sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC; + sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI); + sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC); if (allmulti != sdata_allmulti) { if (dev->flags & IFF_ALLMULTI) @@ -387,6 +800,14 @@ static void ieee80211_set_multicast_list(struct net_device *dev) dev_mc_sync(local->mdev, dev); } +static const struct header_ops ieee80211_header_ops = { + .create = eth_header, + .parse = header_parse_80211, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + /* Must not be called for mdev */ void ieee80211_if_setup(struct net_device *dev) { @@ -407,6 +828,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + DECLARE_MAC_BUF(mac); if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; @@ -415,6 +837,9 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); if (!sta) return -ENOMEM; + + sta->flags |= WLAN_STA_AUTHORIZED; + sta_info_put(sta); /* Remove STA entry for the old peer */ @@ -424,8 +849,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) sta_info_put(sta); } else { printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer " MAC_FMT "\n", - dev->name, MAC_ARG(sdata->u.wds.remote_addr)); + "peer %s\n", + dev->name, print_mac(mac, sdata->u.wds.remote_addr)); } /* Update WDS link data */ @@ -448,20 +873,20 @@ static int __ieee80211_if_config(struct net_device *dev, return 0; memset(&conf, 0, sizeof(conf)); - conf.type = sdata->type; - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + conf.type = sdata->vif.type; + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; - } else if (sdata->type == IEEE80211_IF_TYPE_AP) { + } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; conf.beacon = beacon; conf.beacon_control = control; } return local->ops->config_interface(local_to_hw(local), - dev->ifindex, &conf); + &sdata->vif, &conf); } int ieee80211_if_config(struct net_device *dev) @@ -473,11 +898,13 @@ int ieee80211_if_config_beacon(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_tx_control control; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sk_buff *skb; if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) return 0; - skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control); + skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, + &control); if (!skb) return -ENOMEM; return __ieee80211_if_config(dev, skb, &control); @@ -485,37 +912,28 @@ int ieee80211_if_config_beacon(struct net_device *dev) int ieee80211_hw_config(struct ieee80211_local *local) { - struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan; int ret = 0; - if (local->sta_scanning) { + if (local->sta_sw_scanning) chan = local->scan_channel; - mode = local->scan_hw_mode; - } else { + else chan = local->oper_channel; - mode = local->oper_hw_mode; - } - local->hw.conf.channel = chan->chan; - local->hw.conf.channel_val = chan->val; - if (!local->hw.conf.power_level) { - local->hw.conf.power_level = chan->power_level; - } else { - local->hw.conf.power_level = min(chan->power_level, - local->hw.conf.power_level); - } - local->hw.conf.freq = chan->freq; - local->hw.conf.phymode = mode->mode; - local->hw.conf.antenna_max = chan->antenna_max; - local->hw.conf.chan = chan; - local->hw.conf.mode = mode; + local->hw.conf.channel = chan; + + if (!local->hw.conf.power_level) + local->hw.conf.power_level = chan->max_power; + else + local->hw.conf.power_level = min(chan->max_power, + local->hw.conf.power_level); + + local->hw.conf.max_antenna_gain = chan->max_antenna_gain; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " - "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq, - local->hw.conf.phymode); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", + wiphy_name(local->hw.wiphy), chan->center_freq); +#endif if (local->open_count) ret = local->ops->config(local_to_hw(local), &local->hw.conf); @@ -523,25 +941,81 @@ int ieee80211_hw_config(struct ieee80211_local *local) return ret; } -void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes) +/** + * ieee80211_hw_config_ht should be used only after legacy configuration + * has been determined, as ht configuration depends upon the hardware's + * HT abilities for a _specific_ band. + */ +int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, + struct ieee80211_ht_info *req_ht_cap, + struct ieee80211_ht_bss_info *req_bss_cap) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (local->ops->erp_ie_changed) - local->ops->erp_ie_changed(local_to_hw(local), changes, - !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION), - !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)); + struct ieee80211_conf *conf = &local->hw.conf; + struct ieee80211_supported_band *sband; + int i; + + sband = local->hw.wiphy->bands[conf->channel->band]; + + /* HT is not supported */ + if (!sband->ht_info.ht_supported) { + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + return -EOPNOTSUPP; + } + + /* disable HT */ + if (!enable_ht) { + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + } else { + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; + conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + conf->ht_conf.cap |= + sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + conf->ht_bss_conf.primary_channel = + req_bss_cap->primary_channel; + conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + for (i = 0; i < SUPP_MCS_SET_LEN; i++) + conf->ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + /* In STA mode, this gives us indication + * to the AP's mode of operation */ + conf->ht_conf.ht_supported = 1; + conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density; + } + + local->ops->conf_ht(local_to_hw(local), &local->hw.conf); + + return 0; +} + +void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, + u32 changed) +{ + struct ieee80211_local *local = sdata->local; + + if (!changed) + return; + + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(local_to_hw(local), + &sdata->vif, + &sdata->bss_conf, + changed); } void ieee80211_reset_erp_info(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION | - IEEE80211_SDATA_SHORT_PREAMBLE); - ieee80211_erp_info_change_notify(dev, - IEEE80211_ERP_CHANGE_PROTECTION | - IEEE80211_ERP_CHANGE_PREAMBLE); + sdata->bss_conf.use_cts_prot = 0; + sdata->bss_conf.use_short_preamble = 0; + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_ERP_PREAMBLE); } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, @@ -591,6 +1065,7 @@ static void ieee80211_tasklet_handler(unsigned long data) struct sk_buff *skb; struct ieee80211_rx_status rx_status; struct ieee80211_tx_status *tx_status; + struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { @@ -598,7 +1073,7 @@ static void ieee80211_tasklet_handler(unsigned long data) case IEEE80211_RX_MSG: /* status is in skb->cb */ memcpy(&rx_status, skb->cb, sizeof(rx_status)); - /* Clear skb->type in order to not confuse kernel + /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; __ieee80211_rx(local_to_hw(local), skb, &rx_status); @@ -611,6 +1086,18 @@ static void ieee80211_tasklet_handler(unsigned long data) skb, tx_status); kfree(tx_status); break; + case IEEE80211_DELBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_stop_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break; + case IEEE80211_ADDBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_start_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break ; default: /* should never get here! */ printk(KERN_ERR "%s: Unknown message type (%d)\n", wiphy_name(local->hw.wiphy), skb->pkt_type); @@ -633,7 +1120,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, struct ieee80211_tx_packet_data *pkt_data; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - pkt_data->ifindex = control->ifindex; + pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; pkt_data->flags = 0; if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; @@ -641,6 +1128,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; if (control->flags & IEEE80211_TXCTL_REQUEUE) pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) + pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -695,7 +1184,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, u16 frag, type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; - int monitors; + struct net_device *prev_dev = NULL; if (!status) { printk(KERN_ERR @@ -768,10 +1257,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, sta_info_put(sta); return; } - } else { - /* FIXME: STUPID to call this with both local and local->mdev */ - rate_control_tx_status(local, local->mdev, skb, status); - } + } else + rate_control_tx_status(local->mdev, skb, status); ieee80211_led_tx(local, 0); @@ -810,7 +1297,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); - if (!local->monitors) { + /* + * This is a bit racy but we can avoid a lot of work + * with this test... + */ + if (!local->monitors && !local->cooked_mntrs) { dev_kfree_skb(skb); return; } @@ -844,42 +1335,37 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, rthdr->data_retries = status->retry_count; + /* XXX: is this sufficient for BPF? */ + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + rcu_read_lock(); - monitors = local->monitors; list_for_each_entry_rcu(sdata, &local->interfaces, list) { - /* - * Using the monitors counter is possibly racy, but - * if the value is wrong we simply either clone the skb - * once too much or forget sending it to one monitor iface - * The latter case isn't nice but fixing the race is much - * more complicated. - */ - if (!monitors || !skb) - goto out; - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { if (!netif_running(sdata->dev)) continue; - monitors--; - if (monitors) + + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); - else - skb2 = NULL; - skb->dev = sdata->dev; - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - skb = skb2; + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; } } - out: + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } rcu_read_unlock(); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); @@ -949,9 +1435,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.queues = 1; /* default */ local->mdev = mdev; - local->rx_pre_handlers = ieee80211_rx_pre_handlers; - local->rx_handlers = ieee80211_rx_handlers; - local->tx_handlers = ieee80211_tx_handlers; local->bridge_packets = 1; @@ -961,10 +1444,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; - local->enabled_modes = ~0; - - INIT_LIST_HEAD(&local->modes_list); - INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); @@ -976,10 +1455,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; - mdev->hard_header_parse = header_parse_80211; + mdev->header_ops = &ieee80211_header_ops; mdev->set_multicast_list = ieee80211_master_set_multicast_list; - sdata->type = IEEE80211_IF_TYPE_AP; + sdata->vif.type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; sdata->local = local; sdata->u.ap.force_unicast_rateidx = -1; @@ -1009,6 +1488,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); const char *name; int result; + enum ieee80211_band band; + + /* + * generic code guarantees at least one band, + * set this very early because much code assumes + * that hw.conf.channel is assigned + */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + if (sband) { + /* init channel we're on */ + local->hw.conf.channel = + local->oper_channel = + local->scan_channel = &sband->channels[0]; + break; + } + } result = wiphy_register(local->hw.wiphy); if (result < 0) @@ -1061,7 +1559,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); - result = ieee80211_init_rate_ctrl_alg(local, NULL); + result = ieee80211_init_rate_ctrl_alg(local, + hw->rate_control_algorithm); if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize rate control " "algorithm\n", wiphy_name(local->hw.wiphy)); @@ -1109,44 +1608,10 @@ fail_workqueue: } EXPORT_SYMBOL(ieee80211_register_hw); -int ieee80211_register_hwmode(struct ieee80211_hw *hw, - struct ieee80211_hw_mode *mode) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int i; - - INIT_LIST_HEAD(&mode->list); - list_add_tail(&mode->list, &local->modes_list); - - local->hw_modes |= (1 << mode->mode); - for (i = 0; i < mode->num_rates; i++) { - rate = &(mode->rates[i]); - rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; - } - ieee80211_prepare_rates(local, mode); - - if (!local->oper_hw_mode) { - /* Default to this mode */ - local->hw.conf.phymode = mode->mode; - local->oper_hw_mode = local->scan_hw_mode = mode; - local->oper_channel = local->scan_channel = &mode->channels[0]; - local->hw.conf.mode = local->oper_hw_mode; - local->hw.conf.chan = local->oper_channel; - } - - if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED)) - ieee80211_set_default_regdomain(mode); - - return 0; -} -EXPORT_SYMBOL(ieee80211_register_hwmode); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - int i; tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); @@ -1187,11 +1652,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rate_control_deinitialize(local); debugfs_hw_del(local); - for (i = 0; i < NUM_IEEE80211_MODES; i++) { - kfree(local->supp_rates[i]); - kfree(local->basic_rates[i]); - } - if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", @@ -1222,21 +1682,38 @@ static int __init ieee80211_init(void) BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + ret = rc80211_simple_init(); + if (ret) + goto out; + + ret = rc80211_pid_init(); + if (ret) + goto out_cleanup_simple; + ret = ieee80211_wme_register(); if (ret) { printk(KERN_DEBUG "ieee80211_init: failed to " "initialize WME (err=%d)\n", ret); - return ret; + goto out_cleanup_pid; } ieee80211_debugfs_netdev_init(); - ieee80211_regdomain_init(); return 0; + + out_cleanup_pid: + rc80211_pid_exit(); + out_cleanup_simple: + rc80211_simple_exit(); + out: + return ret; } static void __exit ieee80211_exit(void) { + rc80211_simple_exit(); + rc80211_pid_exit(); + ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit(); } diff --git a/package/mac80211/src/net/mac80211/ieee80211_common.h b/package/mac80211/src/net/mac80211/ieee80211_common.h deleted file mode 100644 index c15295d43d..0000000000 --- a/package/mac80211/src/net/mac80211/ieee80211_common.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * IEEE 802.11 driver (80211.o) -- hostapd interface - * Copyright 2002-2004, Instant802 Networks, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef IEEE80211_COMMON_H -#define IEEE80211_COMMON_H - -#include <linux/types.h> - -/* - * This is common header information with user space. It is used on all - * frames sent to wlan#ap interface. - */ - -#define IEEE80211_FI_VERSION 0x80211001 - -struct ieee80211_frame_info { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; - - /* Note: this structure is otherwise identical to capture format used - * in linux-wlan-ng, but this additional field is used to provide meta - * data about the frame to hostapd. This was the easiest method for - * providing this information, but this might change in the future. */ - __be32 msg_type; -} __attribute__ ((packed)); - - -enum ieee80211_msg_type { - ieee80211_msg_normal = 0, - ieee80211_msg_tx_callback_ack = 1, - ieee80211_msg_tx_callback_fail = 2, - /* hole at 3, was ieee80211_msg_passive_scan but unused */ - /* hole at 4, was ieee80211_msg_wep_frame_unknown_key but now unused */ - ieee80211_msg_michael_mic_failure = 5, - /* hole at 6, was monitor but never sent to userspace */ - ieee80211_msg_sta_not_assoc = 7, - /* 8 was ieee80211_msg_set_aid_for_sta */ - /* 9 was ieee80211_msg_key_threshold_notification */ - /* 11 was ieee80211_msg_radar */ -}; - -struct ieee80211_msg_key_notification { - int tx_rx_count; - char ifname[IFNAMSIZ]; - u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */ -}; - - -enum ieee80211_phytype { - ieee80211_phytype_fhss_dot11_97 = 1, - ieee80211_phytype_dsss_dot11_97 = 2, - ieee80211_phytype_irbaseband = 3, - ieee80211_phytype_dsss_dot11_b = 4, - ieee80211_phytype_pbcc_dot11_b = 5, - ieee80211_phytype_ofdm_dot11_g = 6, - ieee80211_phytype_pbcc_dot11_g = 7, - ieee80211_phytype_ofdm_dot11_a = 8, -}; - -enum ieee80211_ssi_type { - ieee80211_ssi_none = 0, - ieee80211_ssi_norm = 1, /* normalized, 0-1000 */ - ieee80211_ssi_dbm = 2, - ieee80211_ssi_raw = 3, /* raw SSI */ -}; - -struct ieee80211_radar_info { - int channel; - int radar; - int radar_type; -}; - -#endif /* IEEE80211_COMMON_H */ diff --git a/package/mac80211/src/net/mac80211/ieee80211_i.h b/package/mac80211/src/net/mac80211/ieee80211_i.h index d34a9deca6..1b4a449703 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_i.h +++ b/package/mac80211/src/net/mac80211/ieee80211_i.h @@ -37,8 +37,6 @@ struct ieee80211_local; -#define BIT(x) (1 << (x)) - #define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3) /* Maximum number of broadcast/multicast frames to buffer when some of the @@ -81,8 +79,7 @@ struct ieee80211_sta_bss { u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; u16 capability; /* host byte order */ - int hw_mode; - int channel; + enum ieee80211_band band; int freq; int rssi, signal, noise; u8 *wpa_ie; @@ -91,6 +88,8 @@ struct ieee80211_sta_bss { size_t rsn_ie_len; u8 *wmm_ie; size_t wmm_ie_len; + u8 *ht_ie; + size_t ht_ie_len; #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; size_t supp_rates_len; @@ -109,9 +108,17 @@ struct ieee80211_sta_bss { }; -typedef enum { - TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED -} ieee80211_txrx_result; +typedef unsigned __bitwise__ ieee80211_tx_result; +#define TX_CONTINUE ((__force ieee80211_tx_result) 0u) +#define TX_DROP ((__force ieee80211_tx_result) 1u) +#define TX_QUEUED ((__force ieee80211_tx_result) 2u) + +typedef unsigned __bitwise__ ieee80211_rx_result; +#define RX_CONTINUE ((__force ieee80211_rx_result) 0u) +#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) +#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) +#define RX_QUEUED ((__force ieee80211_rx_result) 3u) + /* flags used in struct ieee80211_txrx_data.flags */ /* whether the MSDU was fragmented */ @@ -123,6 +130,8 @@ typedef enum { /* frame is destined to interface currently processed (incl. multicast frames) */ #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) #define IEEE80211_TXRXD_TX_INJECTED BIT(6) +#define IEEE80211_TXRXD_RX_AMSDU BIT(7) +#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; @@ -135,13 +144,12 @@ struct ieee80211_txrx_data { union { struct { struct ieee80211_tx_control *control; - struct ieee80211_hw_mode *mode; + struct ieee80211_channel *channel; struct ieee80211_rate *rate; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; - int last_frag_hwrate; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -150,6 +158,7 @@ struct ieee80211_txrx_data { } tx; struct { struct ieee80211_rx_status *status; + struct ieee80211_rate *rate; int sent_ps_buffered; int queue; int load; @@ -163,6 +172,8 @@ struct ieee80211_txrx_data { #define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) #define IEEE80211_TXPD_REQUEUE BIT(2) +#define IEEE80211_TXPD_EAPOL_FRAME BIT(3) +#define IEEE80211_TXPD_AMPDU BIT(4) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; @@ -176,21 +187,18 @@ struct ieee80211_tx_stored_packet { struct sk_buff *skb; int num_extra_frag; struct sk_buff **extra_frag; - int last_frag_rateidx; - int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; unsigned int last_frag_rate_ctrl_probe; }; -typedef ieee80211_txrx_result (*ieee80211_tx_handler) -(struct ieee80211_txrx_data *tx); - -typedef ieee80211_txrx_result (*ieee80211_rx_handler) -(struct ieee80211_txrx_data *rx); +struct beacon_data { + u8 *head, *tail; + int head_len, tail_len; + int dtim_period; +}; struct ieee80211_if_ap { - u8 *beacon_head, *beacon_tail; - int beacon_head_len, beacon_tail_len; + struct beacon_data *beacon; struct list_head vlans; @@ -203,7 +211,7 @@ struct ieee80211_if_ap { u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; atomic_t num_sta_ps; /* number of stations in PS mode */ struct sk_buff_head ps_bc_buf; - int dtim_period, dtim_count; + int dtim_count; int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ int max_ratectrl_rateidx; /* max TX rateidx for rate control */ int num_beacons; /* number of TXed beacon frames for this BSS */ @@ -232,6 +240,7 @@ struct ieee80211_if_vlan { #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) +#define IEEE80211_STA_PRIVACY_INVOKED BIT(13) struct ieee80211_if_sta { enum { IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, @@ -243,6 +252,8 @@ struct ieee80211_if_sta { u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; + u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; + size_t scan_ssid_len; u16 aid; u16 ap_capab, capab; u8 *extra_ie; /* to be added to the end of AssocReq */ @@ -261,7 +272,6 @@ struct ieee80211_if_sta { unsigned long request; struct sk_buff_head skb_queue; - int key_management_enabled; unsigned long last_probe; #define IEEE80211_AUTH_ALG_OPEN BIT(0) @@ -273,7 +283,7 @@ struct ieee80211_if_sta { unsigned long ibss_join_req; struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ - u32 supp_rates_bits; + u32 supp_rates_bits[IEEE80211_NUM_BANDS]; int wmm_last_param_set; }; @@ -282,15 +292,10 @@ struct ieee80211_if_sta { /* flags used in struct ieee80211_sub_if_data.flags */ #define IEEE80211_SDATA_ALLMULTI BIT(0) #define IEEE80211_SDATA_PROMISC BIT(1) -#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */ -/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon - * generator reports that there are no present stations that cannot support short - * preambles */ -#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3) -#define IEEE80211_SDATA_USERSPACE_MLME BIT(4) +#define IEEE80211_SDATA_USERSPACE_MLME BIT(2) +#define IEEE80211_SDATA_OPERATING_GMODE BIT(3) struct ieee80211_sub_if_data { struct list_head list; - enum ieee80211_if_types type; struct wireless_dev wdev; @@ -303,11 +308,11 @@ struct ieee80211_sub_if_data { unsigned int flags; int drop_unencrypted; - int eapol; /* 0 = process EAPOL frames as normal data frames, - * 1 = send EAPOL frames through wlan#ap to hostapd - * (default) */ - int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized - * port */ + + /* + * basic rates of this AP or the AP we're associated to + */ + u64 basic_rates; u16 sequence; @@ -319,6 +324,15 @@ struct ieee80211_sub_if_data { struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *default_key; + /* + * BSS configuration for this interface. + * + * FIXME: I feel bad putting this here when we already have a + * bss pointer, but the bss pointer is just wrong when + * you have multiple virtual STA mode interfaces... + * This needs to be fixed. + */ + struct ieee80211_bss_conf bss_conf; struct ieee80211_if_ap *bss; /* BSS that this device belongs to */ union { @@ -326,6 +340,7 @@ struct ieee80211_sub_if_data { struct ieee80211_if_wds wds; struct ieee80211_if_vlan vlan; struct ieee80211_if_sta sta; + u32 mntr_flags; } u; int channel_use; int channel_use_raw; @@ -336,8 +351,6 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *eapol; - struct dentry *ieee8021_x; struct dentry *state; struct dentry *bssid; struct dentry *prev_bssid; @@ -356,30 +369,21 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *eapol; - struct dentry *ieee8021_x; struct dentry *num_sta_ps; - struct dentry *dtim_period; struct dentry *dtim_count; struct dentry *num_beacons; struct dentry *force_unicast_rateidx; struct dentry *max_ratectrl_rateidx; struct dentry *num_buffered_multicast; - struct dentry *beacon_head_len; - struct dentry *beacon_tail_len; } ap; struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *eapol; - struct dentry *ieee8021_x; struct dentry *peer; } wds; struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *eapol; - struct dentry *ieee8021_x; } vlan; struct { struct dentry *mode; @@ -387,13 +391,23 @@ struct ieee80211_sub_if_data { struct dentry *default_key; } debugfs; #endif + /* must be last, dynamically sized area in this! */ + struct ieee80211_vif vif; }; +static inline +struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) +{ + return container_of(p, struct ieee80211_sub_if_data, vif); +} + #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) enum { IEEE80211_RX_MSG = 1, IEEE80211_TX_STATUS_MSG = 2, + IEEE80211_DELBA_MSG = 3, + IEEE80211_ADDBA_MSG = 4, }; struct ieee80211_local { @@ -404,12 +418,11 @@ struct ieee80211_local { const struct ieee80211_ops *ops; - /* List of registered struct ieee80211_hw_mode */ - struct list_head modes_list; - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; - int monitors; + int monitors, cooked_mntrs; + /* number of interfaces with corresponding FIF_ flags */ + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; @@ -437,8 +450,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; + unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; + struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ @@ -446,11 +459,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - /* Supported and basic rate filters for different modes. These are - * pointers to -1 terminated lists and rates in 100 kbps units. */ - int *supp_rates[NUM_IEEE80211_MODES]; - int *basic_rates[NUM_IEEE80211_MODES]; - int rts_threshold; int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ @@ -464,29 +472,23 @@ struct ieee80211_local { * deliver multicast frames both back to wireless * media and to the local net stack */ - ieee80211_rx_handler *rx_pre_handlers; - ieee80211_rx_handler *rx_handlers; - ieee80211_tx_handler *tx_handlers; - struct list_head interfaces; - int sta_scanning; + bool sta_sw_scanning; + bool sta_hw_scanning; int scan_channel_idx; + enum ieee80211_band scan_band; + enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; unsigned long last_scan_completed; struct delayed_work scan_work; struct net_device *scan_dev; struct ieee80211_channel *oper_channel, *scan_channel; - struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; struct list_head sta_bss_list; struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE]; spinlock_t sta_bss_lock; -#define IEEE80211_SCAN_MATCH_SSID BIT(0) -#define IEEE80211_SCAN_WPA_ONLY BIT(1) -#define IEEE80211_SCAN_EXTRA_INFO BIT(2) - int scan_flags; /* SNMP counters */ /* dot11CountersTable */ @@ -503,8 +505,9 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_LEDS int tx_led_counter, rx_led_counter; - struct led_trigger *tx_led, *rx_led, *assoc_led; - char tx_led_name[32], rx_led_name[32], assoc_led_name[32]; + struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; + char tx_led_name[32], rx_led_name[32], + assoc_led_name[32], radio_led_name[32]; #endif u32 channel_use; @@ -549,14 +552,8 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - unsigned int enabled_modes; /* bitfield of allowed modes; - * (1 << MODE_*) */ - unsigned int hw_modes; /* bitfield of supported hardware modes; - * (1 << MODE_*) */ - #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { - struct dentry *channel; struct dentry *frequency; struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; @@ -566,9 +563,7 @@ struct ieee80211_local { struct dentry *short_retry_limit; struct dentry *long_retry_limit; struct dentry *total_ps_buffered; - struct dentry *mode; struct dentry *wep_iv; - struct dentry *modes; struct dentry *statistics; struct local_debugfsdentries_statsdentries { struct dentry *transmitted_fragment_count; @@ -616,6 +611,12 @@ struct ieee80211_local { #endif }; +/* this struct represents 802.11n's RA/TID combination */ +struct ieee80211_ra_tid { + u8 ra[ETH_ALEN]; + u16 tid; +}; + static inline struct ieee80211_local *hw_to_local( struct ieee80211_hw *hw) { @@ -673,23 +674,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local, read_unlock_bh(&local->sta_lock); } -/** - * ieee80211_is_erp_rate - Check if a rate is an ERP rate - * @phymode: The PHY-mode for this rate (MODE_IEEE80211...) - * @rate: Transmission rate to check, in 100 kbps - * - * Check if a given rate is an Extended Rate PHY (ERP) rate. - */ -static inline int ieee80211_is_erp_rate(int phymode, int rate) -{ - if (phymode == MODE_IEEE80211G) { - if (rate != 10 && rate != 20 && - rate != 55 && rate != 110) - return 1; - } - return 0; -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { return compare_ether_addr(raddr, addr) == 0 || @@ -701,13 +685,12 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); -struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, - int phymode, int hwrate); +int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, + struct ieee80211_ht_info *req_ht_cap, + struct ieee80211_ht_bss_info *req_bss_cap); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; @@ -735,7 +718,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* ieee80211_ioctl.c */ int ieee80211_set_compression(struct ieee80211_local *local, struct net_device *dev, struct sta_info *sta); -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq); +int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); @@ -749,8 +732,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); -void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_rx_result ieee80211_sta_rx_scan( + struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status); void ieee80211_rx_bss_list_init(struct net_device *dev); void ieee80211_rx_bss_list_deinit(struct net_device *dev); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); @@ -759,9 +743,23 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, u8 *addr); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); -void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes); +void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, + u32 changed); void ieee80211_reset_erp_info(struct net_device *dev); - +int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, + struct ieee80211_ht_info *ht_info); +int ieee80211_ht_addt_info_ie_to_ht_bss_info( + struct ieee80211_ht_addt_info *ht_add_info_ie, + struct ieee80211_ht_bss_info *bss_info); +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout); +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code); +void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, + u16 tid, u16 initiator, u16 reason); +void sta_rx_agg_session_timer_expired(unsigned long data); +void sta_addba_resp_timer_expired(unsigned long data); /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, struct net_device **new_dev, int type); @@ -773,16 +771,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -/* regdomain.c */ -void ieee80211_regdomain_init(void); -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); - -/* rx handling */ -extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; -extern ieee80211_rx_handler ieee80211_rx_handlers[]; - /* tx handling */ -extern ieee80211_tx_handler ieee80211_tx_handlers[]; void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -793,8 +782,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); extern void *mac80211_wiphy_privid; /* for wiphy privid */ extern const unsigned char rfc1042_header[6]; extern const unsigned char bridge_tunnel_header[6]; -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); -int ieee80211_is_eapol(const struct sk_buff *skb); +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, + enum ieee80211_if_types type); int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble); void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, diff --git a/package/mac80211/src/net/mac80211/ieee80211_iface.c b/package/mac80211/src/net/mac80211/ieee80211_iface.c index 43e505d294..f66f1ddc3f 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_iface.c +++ b/package/mac80211/src/net/mac80211/ieee80211_iface.c @@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) /* Default values for sub-interface parameters */ sdata->drop_unencrypted = 0; - sdata->eapol = 1; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) skb_queue_head_init(&sdata->fragments[i].skb_list); @@ -48,7 +47,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name, int ret; ASSERT_RTNL(); - ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), + ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, ieee80211_if_setup); if (!ndev) return -ENOMEM; @@ -67,7 +66,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name, sdata = IEEE80211_DEV_TO_SUB_IF(ndev); ndev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = local->hw.wiphy; - sdata->type = IEEE80211_IF_TYPE_AP; + sdata->vif.type = IEEE80211_IF_TYPE_AP; sdata->dev = ndev; sdata->local = local; ieee80211_if_sdata_init(sdata); @@ -99,7 +98,7 @@ fail: void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int oldtype = sdata->type; + int oldtype = sdata->vif.type; /* * We need to call this function on the master interface @@ -117,7 +116,9 @@ void ieee80211_if_set_type(struct net_device *dev, int type) /* most have no BSS pointer */ sdata->bss = NULL; - sdata->type = type; + sdata->vif.type = type; + + sdata->basic_rates = 0; switch (type) { case IEEE80211_IF_TYPE_WDS: @@ -127,7 +128,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->u.vlan.ap = NULL; break; case IEEE80211_IF_TYPE_AP: - sdata->u.ap.dtim_period = 2; sdata->u.ap.force_unicast_rateidx = -1; sdata->u.ap.max_ratectrl_rateidx = -1; skb_queue_head_init(&sdata->u.ap.ps_bc_buf); @@ -160,6 +160,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_IEEE80211_RADIOTAP; dev->hard_start_xmit = ieee80211_monitor_start_xmit; + sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | + MONITOR_FLAG_OTHER_BSS; break; default: printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", @@ -182,7 +184,7 @@ void ieee80211_if_reinit(struct net_device *dev) ieee80211_if_sdata_deinit(sdata); - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_INVALID: /* cannot happen */ WARN_ON(1); @@ -208,8 +210,7 @@ void ieee80211_if_reinit(struct net_device *dev) } } - kfree(sdata->u.ap.beacon_head); - kfree(sdata->u.ap.beacon_tail); + kfree(sdata->u.ap.beacon); while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { local->total_ps_buffered--; @@ -280,7 +281,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) ASSERT_RTNL(); list_for_each_entry_safe(sdata, n, &local->interfaces, list) { - if ((sdata->type == id || id == -1) && + if ((sdata->vif.type == id || id == -1) && strcmp(name, sdata->dev->name) == 0 && sdata->dev != local->mdev) { list_del_rcu(&sdata->list); diff --git a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c index f95d488726..54ad07aafe 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c +++ b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c @@ -21,6 +21,7 @@ #include <net/mac80211.h> #include "ieee80211_i.h" +#include "ieee80211_led.h" #include "ieee80211_rate.h" #include "wpa.h" #include "aes_ccm.h" @@ -64,9 +65,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, sta = sta_info_get(local, sta_addr); if (!sta) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - MAC_FMT "\n", - dev->name, MAC_ARG(sta_addr)); + "%s\n", + dev->name, print_mac(mac, sta_addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ return -ENOENT; @@ -110,8 +112,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) return -EOPNOTSUPP; - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); if (ret) return ret; @@ -127,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - switch (local->hw.conf.phymode) { - case MODE_IEEE80211A: - strcpy(name, "IEEE 802.11a"); - break; - case MODE_IEEE80211B: - strcpy(name, "IEEE 802.11b"); - break; - case MODE_IEEE80211G: - strcpy(name, "IEEE 802.11g"); - break; - default: - strcpy(name, "IEEE 802.11"); - break; - } + strcpy(name, "IEEE 802.11"); return 0; } @@ -154,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iw_range *range = (struct iw_range *) extra; - struct ieee80211_hw_mode *mode = NULL; + enum ieee80211_band band; int c = 0; data->length = sizeof(struct iw_range); @@ -189,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - list_for_each_entry(mode, &local->modes_list, list) { - int i = 0; - if (!(local->enabled_modes & (1 << mode->mode)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + int i; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + + if (!sband) continue; - while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { - struct ieee80211_channel *chan = &mode->channels[i]; + for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; - if (chan->flag & IEEE80211_CHAN_W_SCAN) { - range->freq[c].i = chan->chan; - range->freq[c].m = chan->freq * 100000; - range->freq[c].e = 1; + if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { + range->freq[c].i = + ieee80211_frequency_to_channel( + chan->center_freq); + range->freq[c].m = chan->center_freq; + range->freq[c].e = 6; c++; } - i++; } } range->num_channels = c; @@ -217,6 +207,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + range->scan_capa |= IW_SCAN_CAPA_ESSID; + return 0; } @@ -228,7 +220,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int type; - if (sdata->type == IEEE80211_IF_TYPE_VLAN) + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) return -EOPNOTSUPP; switch (*mode) { @@ -245,7 +237,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev, return -EINVAL; } - if (type == sdata->type) + if (type == sdata->vif.type) return 0; if (netif_running(dev)) return -EBUSY; @@ -264,7 +256,7 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_AP: *mode = IW_MODE_MASTER; break; @@ -290,28 +282,38 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, return 0; } -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) +int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) { - struct ieee80211_hw_mode *mode; - int c, set = 0; + int set = 0; int ret = -EINVAL; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + int i; - list_for_each_entry(mode, &local->modes_list, list) { - if (!(local->enabled_modes & (1 << mode->mode))) + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + sband = local->hw.wiphy->bands[band]; + + if (!sband) continue; - for (c = 0; c < mode->num_channels; c++) { - struct ieee80211_channel *chan = &mode->channels[c]; - if (chan->flag & IEEE80211_CHAN_W_SCAN && - ((chan->chan == channel) || (chan->freq == freq))) { + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (chan->center_freq == freqMHz) { + set = 1; local->oper_channel = chan; - local->oper_hw_mode = mode; - set++; + break; } } + if (set) + break; } if (set) { - if (local->sta_scanning) + if (local->sta_sw_scanning) ret = 0; else ret = ieee80211_hw_config(local); @@ -329,24 +331,25 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA) + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { - if (sdata->type == IEEE80211_IF_TYPE_STA) + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sdata->u.sta.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else - return ieee80211_set_channel(local, freq->m, -1); + return ieee80211_set_freq(local, + ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div > 0) - return ieee80211_set_channel(local, -1, freq->m / div); + return ieee80211_set_freq(local, freq->m / div); else return -EINVAL; } @@ -359,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level - * driver for the current channel with firmware-based management */ - - freq->m = local->hw.conf.freq; + freq->m = local->hw.conf.channel->center_freq; freq->e = 6; return 0; @@ -381,8 +381,8 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, len--; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { int ret; if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { if (len > IEEE80211_MAX_SSID_LEN) @@ -402,7 +402,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, return 0; } - if (sdata->type == IEEE80211_IF_TYPE_AP) { + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { memcpy(sdata->u.ap.ssid, ssid, len); memset(sdata->u.ap.ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); @@ -421,8 +421,8 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { int res = ieee80211_sta_get_ssid(dev, ssid, &len); if (res == 0) { data->length = len; @@ -432,7 +432,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, return res; } - if (sdata->type == IEEE80211_IF_TYPE_AP) { + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { len = sdata->u.ap.ssid_len; if (len > IW_ESSID_MAX_SIZE) len = IW_ESSID_MAX_SIZE; @@ -452,8 +452,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { int ret; if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, @@ -472,7 +472,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, return ret; ieee80211_sta_req_auth(dev, &sdata->u.sta); return 0; - } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { + } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, ETH_ALEN) == 0) return 0; @@ -490,12 +490,12 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); return 0; - } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { + } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); return 0; @@ -507,32 +507,27 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, static int ieee80211_ioctl_siwscan(struct net_device *dev, struct iw_request_info *info, - struct iw_point *data, char *extra) + union iwreq_data *wrqu, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct iw_scan_req *req = NULL; u8 *ssid = NULL; size_t ssid_len = 0; if (!netif_running(dev)) return -ENETDOWN; - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) { - ssid = sdata->u.sta.ssid; - ssid_len = sdata->u.sta.ssid_len; - } - break; - case IEEE80211_IF_TYPE_AP: - if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) { - ssid = sdata->u.ap.ssid; - ssid_len = sdata->u.ap.ssid_len; - } - break; - default: + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_AP) return -EOPNOTSUPP; + + /* if SSID was specified explicitly then use that */ + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req *)extra; + ssid = req->essid; + ssid_len = req->essid_len; } return ieee80211_sta_req_scan(dev, ssid, ssid_len); @@ -545,8 +540,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev, { int res; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (local->sta_scanning) + + if (local->sta_sw_scanning || local->sta_hw_scanning) return -EAGAIN; + res = ieee80211_sta_scan_results(dev, extra, data->length); if (res >= 0) { data->length = res; @@ -562,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; - int i; + int i, err = -EINVAL; u32 target_rate = rate->value / 100000; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata->bss) return -ENODEV; - mode = local->oper_hw_mode; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 0 means all rates <= X */ @@ -578,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, sdata->bss->force_unicast_rateidx = -1; if (rate->value < 0) return 0; - for (i=0; i< mode->num_rates; i++) { - struct ieee80211_rate *rates = &mode->rates[i]; - int this_rate = rates->rate; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) sdata->bss->force_unicast_rateidx = i; + err = 0; break; } } - return 0; + return err; } static int ieee80211_ioctl_giwrate(struct net_device *dev, @@ -599,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_STA) + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sta = sta_info_get(local, sdata->u.sta.bssid); else return -EOPNOTSUPP; if (!sta) return -ENODEV; - if (sta->txrate < local->oper_hw_mode->num_rates) - rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + if (sta->txrate_idx < sband->n_bitrates) + rate->value = sband->bitrates[sta->txrate_idx].bitrate; else rate->value = 0; + rate->value *= 100000; sta_info_put(sta); return 0; } @@ -621,22 +628,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); bool need_reconfig = 0; + int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; - if (!data->txpower.fixed) - return -EINVAL; - if (local->hw.conf.power_level != data->txpower.value) { - local->hw.conf.power_level = data->txpower.value; + if (data->txpower.fixed) { + new_power_level = data->txpower.value; + } else { + /* + * Automatic power level. Use maximum power for the current + * channel. Should be part of rate control. + */ + struct ieee80211_channel* chan = local->hw.conf.channel; + if (!chan) + return -EINVAL; + + new_power_level = chan->max_power; + } + + if (local->hw.conf.power_level != new_power_level) { + local->hw.conf.power_level = new_power_level; need_reconfig = 1; } + if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { local->hw.conf.radio_enabled = !(data->txpower.disabled); need_reconfig = 1; + ieee80211_led_radio(local, local->hw.conf.radio_enabled); } + if (need_reconfig) { ieee80211_hw_config(local); /* The return value of hw_config is not of big interest here, @@ -801,8 +824,8 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev, struct iw_mlme *mlme = (struct iw_mlme *) extra; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) return -EINVAL; switch (mlme->cmd) { @@ -904,7 +927,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret = 0; @@ -914,32 +936,33 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, case IW_AUTH_CIPHER_GROUP: case IW_AUTH_WPA_ENABLED: case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; case IW_AUTH_KEY_MGMT: - if (sdata->type != IEEE80211_IF_TYPE_STA) + break; + case IW_AUTH_DROP_UNENCRYPTED: + sdata->drop_unencrypted = !!data->value; + break; + case IW_AUTH_PRIVACY_INVOKED: + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) ret = -EINVAL; else { + sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; /* - * Key management was set by wpa_supplicant, - * we only need this to associate to a network - * that has privacy enabled regardless of not - * having a key. + * Privacy invoked by wpa_supplicant, store the + * value and allow associating to a protected + * network without having a key up front. */ - sdata->u.sta.key_management_enabled = !!data->value; + if (data->value) + sdata->u.sta.flags |= + IEEE80211_STA_PRIVACY_INVOKED; } break; case IW_AUTH_80211_AUTH_ALG: - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) sdata->u.sta.auth_algs = data->value; else ret = -EOPNOTSUPP; break; - case IW_AUTH_PRIVACY_INVOKED: - if (local->ops->set_privacy_invoked) - ret = local->ops->set_privacy_invoked( - local_to_hw(local), data->value); - break; default: ret = -EOPNOTSUPP; break; @@ -955,8 +978,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta = NULL; - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) sta = sta_info_get(local, sdata->u.sta.bssid); if (!sta) { wstats->discard.fragment = 0; @@ -984,8 +1007,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, switch (data->flags & IW_AUTH_INDEX) { case IW_AUTH_80211_AUTH_ALG: - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) data->value = sdata->u.sta.auth_algs; else ret = -EOPNOTSUPP; diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.c b/package/mac80211/src/net/mac80211/ieee80211_led.c index 4cf89af9d1..f401484ab6 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_led.c +++ b/package/mac80211/src/net/mac80211/ieee80211_led.c @@ -43,6 +43,16 @@ void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) led_trigger_event(local->assoc_led, LED_OFF); } +void ieee80211_led_radio(struct ieee80211_local *local, bool enabled) +{ + if (unlikely(!local->radio_led)) + return; + if (enabled) + led_trigger_event(local->radio_led, LED_FULL); + else + led_trigger_event(local->radio_led, LED_OFF); +} + void ieee80211_led_init(struct ieee80211_local *local) { local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); @@ -77,10 +87,25 @@ void ieee80211_led_init(struct ieee80211_local *local) local->assoc_led = NULL; } } + + local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->radio_led) { + snprintf(local->radio_led_name, sizeof(local->radio_led_name), + "%sradio", wiphy_name(local->hw.wiphy)); + local->radio_led->name = local->radio_led_name; + if (led_trigger_register(local->radio_led)) { + kfree(local->radio_led); + local->radio_led = NULL; + } + } } void ieee80211_led_exit(struct ieee80211_local *local) { + if (local->radio_led) { + led_trigger_unregister(local->radio_led); + kfree(local->radio_led); + } if (local->assoc_led) { led_trigger_unregister(local->assoc_led); kfree(local->assoc_led); @@ -95,6 +120,16 @@ void ieee80211_led_exit(struct ieee80211_local *local) } } +char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->radio_led) + return local->radio_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_radio_led_name); + char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.h b/package/mac80211/src/net/mac80211/ieee80211_led.h index 0feb226198..77b1e1ba60 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_led.h +++ b/package/mac80211/src/net/mac80211/ieee80211_led.h @@ -16,6 +16,8 @@ extern void ieee80211_led_rx(struct ieee80211_local *local); extern void ieee80211_led_tx(struct ieee80211_local *local, int q); extern void ieee80211_led_assoc(struct ieee80211_local *local, bool associated); +extern void ieee80211_led_radio(struct ieee80211_local *local, + bool enabled); extern void ieee80211_led_init(struct ieee80211_local *local); extern void ieee80211_led_exit(struct ieee80211_local *local); #else @@ -29,6 +31,10 @@ static inline void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) { } +static inline void ieee80211_led_radio(struct ieee80211_local *local, + bool enabled) +{ +} static inline void ieee80211_led_init(struct ieee80211_local *local) { } diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.c b/package/mac80211/src/net/mac80211/ieee80211_rate.c index 93abb8fff1..ebe29b716b 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_rate.c +++ b/package/mac80211/src/net/mac80211/ieee80211_rate.c @@ -21,17 +21,35 @@ struct rate_control_alg { static LIST_HEAD(rate_ctrl_algs); static DEFINE_MUTEX(rate_ctrl_mutex); +static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT; +module_param(ieee80211_default_rc_algo, charp, 0644); +MODULE_PARM_DESC(ieee80211_default_rc_algo, + "Default rate control algorithm for mac80211 to use"); + int ieee80211_rate_control_register(struct rate_control_ops *ops) { struct rate_control_alg *alg; + if (!ops->name) + return -EINVAL; + + mutex_lock(&rate_ctrl_mutex); + list_for_each_entry(alg, &rate_ctrl_algs, list) { + if (!strcmp(alg->ops->name, ops->name)) { + /* don't register an algorithm twice */ + WARN_ON(1); + mutex_unlock(&rate_ctrl_mutex); + return -EALREADY; + } + } + alg = kzalloc(sizeof(*alg), GFP_KERNEL); if (alg == NULL) { + mutex_unlock(&rate_ctrl_mutex); return -ENOMEM; } alg->ops = ops; - mutex_lock(&rate_ctrl_mutex); list_add_tail(&alg->list, &rate_ctrl_algs); mutex_unlock(&rate_ctrl_mutex); @@ -47,11 +65,11 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops) list_for_each_entry(alg, &rate_ctrl_algs, list) { if (alg->ops == ops) { list_del(&alg->list); + kfree(alg); break; } } mutex_unlock(&rate_ctrl_mutex); - kfree(alg); } EXPORT_SYMBOL(ieee80211_rate_control_unregister); @@ -61,9 +79,12 @@ ieee80211_try_rate_control_ops_get(const char *name) struct rate_control_alg *alg; struct rate_control_ops *ops = NULL; + if (!name) + return NULL; + mutex_lock(&rate_ctrl_mutex); list_for_each_entry(alg, &rate_ctrl_algs, list) { - if (!name || !strcmp(alg->ops->name, name)) + if (!strcmp(alg->ops->name, name)) if (try_module_get(alg->ops->module)) { ops = alg->ops; break; @@ -73,18 +94,31 @@ ieee80211_try_rate_control_ops_get(const char *name) return ops; } -/* Get the rate control algorithm. If `name' is NULL, get the first - * available algorithm. */ +/* Get the rate control algorithm. */ static struct rate_control_ops * ieee80211_rate_control_ops_get(const char *name) { struct rate_control_ops *ops; + const char *alg_name; - ops = ieee80211_try_rate_control_ops_get(name); + if (!name) + alg_name = ieee80211_default_rc_algo; + else + alg_name = name; + + ops = ieee80211_try_rate_control_ops_get(alg_name); if (!ops) { - request_module("rc80211_%s", name ? name : "default"); - ops = ieee80211_try_rate_control_ops_get(name); + request_module("rc80211_%s", alg_name); + ops = ieee80211_try_rate_control_ops_get(alg_name); } + if (!ops && name) + /* try default if specific alg requested but not found */ + ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); + + /* try built-in one if specific alg requested but not found */ + if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) + ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); + return ops; } @@ -128,6 +162,38 @@ static void rate_control_release(struct kref *kref) kfree(ctrl_ref); } +void rate_control_get_rate(struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct rate_control_ref *ref = local->rate_ctrl; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct sta_info *sta = sta_info_get(local, hdr->addr1); + int i; + + memset(sel, 0, sizeof(struct rate_selection)); + + ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + + /* Select a non-ERP backup rate. */ + if (!sel->nonerp) { + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + if (sel->rate->bitrate < rate->bitrate) + break; + + if (rate_supported(sta, sband->band, i) && + !(rate->flags & IEEE80211_RATE_ERP_G)) + sel->nonerp = rate; + } + } + + if (sta) + sta_info_put(sta); +} + struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) { kref_get(&ref->kref); @@ -178,3 +244,4 @@ void rate_control_deinitialize(struct ieee80211_local *local) local->rate_ctrl = NULL; rate_control_put(ref); } + diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.h b/package/mac80211/src/net/mac80211/ieee80211_rate.h index 7cd1ebab4f..5f9a2ca49a 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_rate.h +++ b/package/mac80211/src/net/mac80211/ieee80211_rate.h @@ -18,31 +18,26 @@ #include "ieee80211_i.h" #include "sta_info.h" -#define RATE_CONTROL_NUM_DOWN 20 -#define RATE_CONTROL_NUM_UP 15 - - -struct rate_control_extra { - /* values from rate_control_get_rate() to the caller: */ - struct ieee80211_rate *probe; /* probe with this rate, or NULL for no - * probing */ +/* TODO: kdoc */ +struct rate_selection { + /* Selected transmission rate */ + struct ieee80211_rate *rate; + /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ struct ieee80211_rate *nonerp; - - /* parameters from the caller to rate_control_get_rate(): */ - struct ieee80211_hw_mode *mode; - u16 ethertype; + /* probe with this rate, or NULL for no probing */ + struct ieee80211_rate *probe; }; - struct rate_control_ops { struct module *module; const char *name; void (*tx_status)(void *priv, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *status); - struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct rate_control_extra *extra); + void (*get_rate)(void *priv, struct net_device *dev, + struct ieee80211_supported_band *band, + struct sk_buff *skb, + struct rate_selection *sel); void (*rate_init)(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta); void (*clear)(void *priv); @@ -72,25 +67,21 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops); * first available algorithm. */ struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local); +void rate_control_get_rate(struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); -static inline void rate_control_tx_status(struct ieee80211_local *local, - struct net_device *dev, +static inline void rate_control_tx_status(struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *status) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->tx_status(ref->priv, dev, skb, status); -} - -static inline struct ieee80211_rate * -rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev, - struct sk_buff *skb, struct rate_control_extra *extra) -{ - struct rate_control_ref *ref = local->rate_ctrl; - return ref->ops->get_rate(ref->priv, dev, skb, extra); + ref->ops->tx_status(ref->priv, dev, skb, status); } @@ -139,10 +130,74 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } +static inline int rate_supported(struct sta_info *sta, + enum ieee80211_band band, + int index) +{ + return (sta == NULL || sta->supp_rates[band] & BIT(index)); +} + +static inline int +rate_lowest_index(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, + struct sta_info *sta) +{ + int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return i; + + /* warn when we cannot find a rate. */ + WARN_ON(1); + + return 0; +} + +static inline struct ieee80211_rate * +rate_lowest(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, + struct sta_info *sta) +{ + return &sband->bitrates[rate_lowest_index(local, sband, sta)]; +} + /* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name); void rate_control_deinitialize(struct ieee80211_local *local); + +/* Rate control algorithms */ +#if defined(RC80211_SIMPLE_COMPILE) || \ + (defined(CONFIG_MAC80211_RC_SIMPLE) && \ + !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE)) +extern int rc80211_simple_init(void); +extern void rc80211_simple_exit(void); +#else +static inline int rc80211_simple_init(void) +{ + return 0; +} +static inline void rc80211_simple_exit(void) +{ +} +#endif + +#if defined(RC80211_PID_COMPILE) || \ + (defined(CONFIG_MAC80211_RC_PID) && \ + !defined(CONFIG_MAC80211_RC_PID_MODULE)) +extern int rc80211_pid_init(void); +extern void rc80211_pid_exit(void); +#else +static inline int rc80211_pid_init(void) +{ + return 0; +} +static inline void rc80211_pid_exit(void) +{ +} +#endif + #endif /* IEEE80211_RATE_H */ diff --git a/package/mac80211/src/net/mac80211/ieee80211_sta.c b/package/mac80211/src/net/mac80211/ieee80211_sta.c index 7c93f29c8b..92d7450e2c 100644 --- a/package/mac80211/src/net/mac80211/ieee80211_sta.c +++ b/package/mac80211/src/net/mac80211/ieee80211_sta.c @@ -12,7 +12,6 @@ */ /* TODO: - * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs * order BSS list by RSSI(?) ("quality of AP") * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, * SSID) @@ -58,10 +57,25 @@ #define ERP_INFO_USE_PROTECTION BIT(1) +/* mgmt header + 1 byte action code */ +#define IEEE80211_MIN_ACTION_SIZE (24 + 1) + +#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 +#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 + +/* next values represent the buffer size for A-MPDU frame. + * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */ +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_MAX_AMPDU_BUF 0x40 + static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len); static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid); +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len); static void ieee80211_rx_bss_put(struct net_device *dev, struct ieee80211_sta_bss *bss); static int ieee80211_sta_find_ibss(struct net_device *dev, @@ -90,7 +104,8 @@ struct ieee802_11_elems { u8 *ext_supp_rates; u8 *wmm_info; u8 *wmm_param; - + u8 *ht_cap_elem; + u8 *ht_info_elem; /* length of them, respectively */ u8 ssid_len; u8 supp_rates_len; @@ -106,16 +121,15 @@ struct ieee802_11_elems { u8 ext_supp_rates_len; u8 wmm_info_len; u8 wmm_param_len; + u8 ht_cap_elem_len; + u8 ht_info_elem_len; }; -enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 }; - -static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, - struct ieee802_11_elems *elems) +static void ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems) { size_t left = len; u8 *pos = start; - int unknown = 0; memset(elems, 0, sizeof(*elems)); @@ -126,15 +140,8 @@ static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, elen = *pos++; left -= 2; - if (elen > left) { -#if 0 - if (net_ratelimit()) - printk(KERN_DEBUG "IEEE 802.11 element parse " - "failed (id=%d elen=%d left=%d)\n", - id, elen, left); -#endif - return ParseFailed; - } + if (elen > left) + return; switch (id) { case WLAN_EID_SSID: @@ -200,29 +207,24 @@ static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, elems->ext_supp_rates = pos; elems->ext_supp_rates_len = elen; break; + case WLAN_EID_HT_CAPABILITY: + elems->ht_cap_elem = pos; + elems->ht_cap_elem_len = elen; + break; + case WLAN_EID_HT_EXTRA_INFO: + elems->ht_info_elem = pos; + elems->ht_info_elem_len = elen; + break; default: -#if 0 - printk(KERN_DEBUG "IEEE 802.11 element parse ignored " - "unknown element (id=%d elen=%d)\n", - id, elen); -#endif - unknown++; break; } left -= elen; pos += elen; } - - /* Do not trigger error if left == 1 as Apple Airport base stations - * send AssocResps that are one spurious byte too long. */ - - return unknown ? ParseUnknown : ParseOK; } - - static int ecw2cw(int ecw) { int cw = 1; @@ -311,49 +313,89 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, } -static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) +static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, + u8 erp_value) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; struct ieee80211_if_sta *ifsta = &sdata->u.sta; - int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; - u8 changes = 0; + bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + bool preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; + DECLARE_MAC_BUF(mac); + u32 changed = 0; - if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) { + if (use_protection != bss_conf->use_cts_prot) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - MAC_FMT ")\n", - dev->name, + "%s)\n", + sdata->dev->name, use_protection ? "enabled" : "disabled", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } - if (use_protection) - sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; - else - sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION; - changes |= IEEE80211_ERP_CHANGE_PROTECTION; + bss_conf->use_cts_prot = use_protection; + changed |= BSS_CHANGED_ERP_CTS_PROT; } - if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) { + if (preamble_mode != bss_conf->use_short_preamble) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=" MAC_FMT ")\n", - dev->name, + " (BSSID=%s)\n", + sdata->dev->name, (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? "short" : "long", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } - if (preamble_mode) - sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; - else - sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; - changes |= IEEE80211_ERP_CHANGE_PREAMBLE; + bss_conf->use_short_preamble = preamble_mode; + changed |= BSS_CHANGED_ERP_PREAMBLE; } - if (changes) - ieee80211_erp_info_change_notify(dev, changes); + return changed; +} + +int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, + struct ieee80211_ht_info *ht_info) +{ + + if (ht_info == NULL) + return -EINVAL; + + memset(ht_info, 0, sizeof(*ht_info)); + + if (ht_cap_ie) { + u8 ampdu_info = ht_cap_ie->ampdu_params_info; + + ht_info->ht_supported = 1; + ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); + ht_info->ampdu_factor = + ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; + ht_info->ampdu_density = + (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; + memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); + } else + ht_info->ht_supported = 0; + + return 0; } +int ieee80211_ht_addt_info_ie_to_ht_bss_info( + struct ieee80211_ht_addt_info *ht_add_info_ie, + struct ieee80211_ht_bss_info *bss_info) +{ + if (bss_info == NULL) + return -EINVAL; + + memset(bss_info, 0, sizeof(*bss_info)); + + if (ht_add_info_ie) { + u16 op_mode; + op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); + + bss_info->primary_channel = ht_add_info_ie->control_chan; + bss_info->bss_cap = ht_add_info_ie->ht_param; + bss_info->bss_op_mode = (u8)(op_mode & 0xff); + } + + return 0; +} static void ieee80211_sta_send_associnfo(struct net_device *dev, struct ieee80211_if_sta *ifsta) @@ -410,26 +452,26 @@ static void ieee80211_set_associated(struct net_device *dev, struct ieee80211_if_sta *ifsta, bool assoc) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; union iwreq_data wrqu; - - if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc) - return; + u32 changed = BSS_CHANGED_ASSOC; if (assoc) { - struct ieee80211_sub_if_data *sdata; struct ieee80211_sta_bss *bss; ifsta->flags |= IEEE80211_STA_ASSOCIATED; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type != IEEE80211_IF_TYPE_STA) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return; - bss = ieee80211_rx_bss_get(dev, ifsta->bssid); + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->has_erp_value) - ieee80211_handle_erp_ie(dev, bss->erp_value); + changed |= ieee80211_handle_erp_ie( + sdata, bss->erp_value); ieee80211_rx_bss_put(dev, bss); } @@ -449,6 +491,9 @@ static void ieee80211_set_associated(struct net_device *dev, wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); ifsta->last_probe = jiffies; ieee80211_led_assoc(local, assoc); + + sdata->bss_conf.assoc = assoc; + ieee80211_bss_info_change_notify(sdata, changed); } static void ieee80211_set_disassoc(struct net_device *dev, @@ -523,18 +568,20 @@ static void ieee80211_send_auth(struct net_device *dev, static void ieee80211_authenticate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->auth_tries++; if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT + printk(KERN_DEBUG "%s: authentication with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: authenticate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); @@ -546,7 +593,6 @@ static void ieee80211_send_assoc(struct net_device *dev, struct ieee80211_if_sta *ifsta) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *ies; @@ -554,6 +600,7 @@ static void ieee80211_send_assoc(struct net_device *dev, u16 capab; struct ieee80211_sta_bss *bss; int wmm = 0; + struct ieee80211_supported_band *sband; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + ifsta->extra_ie_len + @@ -565,13 +612,20 @@ static void ieee80211_send_assoc(struct net_device *dev, } skb_reserve(skb, local->hw.extra_tx_headroom); - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + capab = ifsta->capab; - if (mode->mode == MODE_IEEE80211G) { - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | - WLAN_CAPABILITY_SHORT_PREAMBLE; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(dev, ifsta->bssid); + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; @@ -609,23 +663,23 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = ifsta->ssid_len; memcpy(pos, ifsta->ssid, ifsta->ssid_len); - len = mode->num_rates; + len = sband->n_bitrates; if (len > 8) len = 8; pos = skb_put(skb, len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = len; for (i = 0; i < len; i++) { - int rate = mode->rates[i].rate; + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } - if (mode->num_rates > len) { - pos = skb_put(skb, mode->num_rates - len + 2); + if (sband->n_bitrates > len) { + pos = skb_put(skb, sband->n_bitrates - len + 2); *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = mode->num_rates - len; - for (i = len; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + *pos++ = sband->n_bitrates - len; + for (i = len; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } } @@ -647,6 +701,20 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = 1; /* WME ver */ *pos++ = 0; } + /* wmm support is a must to HT */ + if (wmm && sband->ht_info.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_info.cap); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_info.ampdu_factor | + (sband->ht_info.ampdu_density << 2); + memcpy(pos, sband->ht_info.supp_mcs_set, 16); + } kfree(ifsta->assocreq_ies); ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; @@ -719,42 +787,51 @@ static void ieee80211_send_disassoc(struct net_device *dev, static int ieee80211_privacy_mismatch(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; - int res = 0; + int bss_privacy; + int wep_privacy; + int privacy_invoked; - if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) || - ifsta->key_management_enabled) + if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) return 0; - bss = ieee80211_rx_bss_get(dev, ifsta->bssid); + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); if (!bss) return 0; - if (ieee80211_sta_wep_configured(dev) != - !!(bss->capability & WLAN_CAPABILITY_PRIVACY)) - res = 1; + bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); + wep_privacy = !!ieee80211_sta_wep_configured(dev); + privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); ieee80211_rx_bss_put(dev, bss); - return res; + if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) + return 0; + + return 1; } static void ieee80211_associate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->assoc_tries++; if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP " MAC_FMT + printk(KERN_DEBUG "%s: association with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: associate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); if (ieee80211_privacy_mismatch(dev, ifsta)) { printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", dev->name); @@ -774,6 +851,7 @@ static void ieee80211_associated(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; int disassoc; + DECLARE_MAC_BUF(mac); /* TODO: start monitoring current AP signal quality and number of * missed beacons. Scan other channels every now and then and search @@ -784,8 +862,8 @@ static void ieee80211_associated(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; } else { disassoc = 0; @@ -793,9 +871,9 @@ static void ieee80211_associated(struct net_device *dev, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP " MAC_FMT " - assume out of " + "current AP %s - assume out of " "range\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; sta_info_free(sta); } else @@ -816,12 +894,8 @@ static void ieee80211_associated(struct net_device *dev, sta_info_put(sta); } if (disassoc) { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); - mod_timer(&ifsta->timer, jiffies + - IEEE80211_MONITORING_INTERVAL + 30 * HZ); + ifsta->state = IEEE80211_DISABLED; + ieee80211_set_associated(dev, ifsta, 0); } else { mod_timer(&ifsta->timer, jiffies + IEEE80211_MONITORING_INTERVAL); @@ -833,7 +907,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *supp_rates, *esupp_rates = NULL; @@ -867,11 +941,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, supp_rates = skb_put(skb, 2); supp_rates[0] = WLAN_EID_SUPP_RATES; supp_rates[1] = 0; - mode = local->oper_hw_mode; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - if (!(rate->flags & IEEE80211_RATE_SUPPORTED)) - continue; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; if (esupp_rates) { pos = skb_put(skb, 1); esupp_rates[1]++; @@ -884,7 +957,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, pos = skb_put(skb, 1); supp_rates[1]++; } - *pos = rate->rate / 5; + *pos = rate->bitrate / 5; } ieee80211_sta_tx(dev, skb, 0); @@ -920,12 +993,7 @@ static void ieee80211_auth_challenge(struct net_device *dev, printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name); pos = mgmt->u.auth.variable; - if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) - == ParseFailed) { - printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n", - dev->name); - return; - } + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.challenge) { printk(KERN_DEBUG "%s: no challenge IE in shared key auth " "frame\n", dev->name); @@ -935,6 +1003,503 @@ static void ieee80211_auth_challenge(struct net_device *dev, elems.challenge_len + 2, 1); } +static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, + u8 dialog_token, u16 status, u16 policy, + u16 buf_size, u16 timeout) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_resp)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer " + "for addba resp frame\n", dev->name); + return; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; + mgmt->u.action.u.addba_resp.dialog_token = dialog_token; + + capab = (u16)(policy << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ + + mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); + mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); + + ieee80211_sta_tx(dev, skb, 0); + + return; +} + +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_req)); + + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for addba request frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; + + mgmt->u.action.u.addba_req.dialog_token = dialog_token; + capab = (u16)(1 << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ + + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + + mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_req.start_seq_num = + cpu_to_le16(start_seq_num << 4); + + ieee80211_sta_tx(dev, skb, 0); +} + +static void ieee80211_sta_process_addba_request(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_conf *conf = &hw->conf; + struct sta_info *sta; + struct tid_ampdu_rx *tid_agg_rx; + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; + u8 dialog_token; + int ret = -EOPNOTSUPP; + DECLARE_MAC_BUF(mac); + + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return; + + /* extract session parameters from addba request frame */ + dialog_token = mgmt->u.action.u.addba_req.dialog_token; + timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); + start_seq_num = + le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; + + capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; + + status = WLAN_STATUS_REQUEST_DECLINED; + + /* sanity check for incoming parameters: + * check if configuration can support the BA policy + * and if buffer size does not exceeds max value */ + if (((ba_policy != 1) + && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) + || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { + status = WLAN_STATUS_INVALID_QOS_PARAM; +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "Block Ack Req with bad params from " + "%s on tid %u. policy %d, buffer size %d\n", + print_mac(mac, mgmt->sa), tid, ba_policy, + buf_size); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto end_no_lock; + } + /* determine default buffer size */ + if (buf_size == 0) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[conf->channel->band]; + buf_size = IEEE80211_MIN_AMPDU_BUF; + buf_size = buf_size << sband->ht_info.ampdu_factor; + } + + tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid]; + + /* examine state machine */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + + if (tid_agg_rx->state != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "unexpected Block Ack Req from " + "%s on tid %u\n", + print_mac(mac, mgmt->sa), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto end; + } + + /* prepare reordering buffer */ + tid_agg_rx->reorder_buf = + kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC); + if ((!tid_agg_rx->reorder_buf) && net_ratelimit()) { + printk(KERN_ERR "can not allocate reordering buffer " + "to tid %d\n", tid); + goto end; + } + memset(tid_agg_rx->reorder_buf, 0, + buf_size * sizeof(struct sk_buf *)); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, + sta->addr, tid, &start_seq_num); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + if (ret) { + kfree(tid_agg_rx->reorder_buf); + goto end; + } + + /* change state and send addba resp */ + tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL; + tid_agg_rx->dialog_token = dialog_token; + tid_agg_rx->ssn = start_seq_num; + tid_agg_rx->head_seq_num = start_seq_num; + tid_agg_rx->buf_size = buf_size; + tid_agg_rx->timeout = timeout; + tid_agg_rx->stored_mpdu_num = 0; + status = WLAN_STATUS_SUCCESS; +end: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + +end_no_lock: + ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, + status, 1, buf_size, timeout); + sta_info_put(sta); +} + +static void ieee80211_sta_process_addba_resp(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u16 capab; + u16 tid; + u8 *state; + + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return; + + capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (mgmt->u.action.u.addba_resp.dialog_token != + sta->ampdu_mlme.tid_tx[tid].dialog_token) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + sta_info_put(sta); + return; + } + + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) + == WLAN_STATUS_SUCCESS) { + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" + "%d\n", *state); + sta_info_put(sta); + return; + } + + if (*state & HT_ADDBA_RECEIVED_MSK) + printk(KERN_DEBUG "double addBA response\n"); + + *state |= HT_ADDBA_RECEIVED_MSK; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); + } else { + printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); + + sta->ampdu_mlme.tid_tx[tid].addba_req_num++; + /* this will allow the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, sta->addr, tid, + WLAN_BACK_INITIATOR); + } + sta_info_put(sta); +} + +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 params; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.delba)); + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for delba frame\n", dev->name); + return; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; + params = (u16)(initiator << 11); /* bit 11 initiator */ + params |= (u16)(tid << 12); /* bit 15:12 TID number */ + + mgmt->u.action.u.delba.params = cpu_to_le16(params); + mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); + + ieee80211_sta_tx(dev, skb, 0); +} + +void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, + u16 initiator, u16 reason) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + int ret, i; + + sta = sta_info_get(local, ra); + if (!sta) + return; + + /* check if TID is in operational state */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + if (sta->ampdu_mlme.tid_rx[tid].state + != HT_AGG_STATE_OPERATIONAL) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + sta_info_put(sta); + return; + } + sta->ampdu_mlme.tid_rx[tid].state = + HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + + /* stop HW Rx aggregation. ampdu_action existence + * already verified in session init so we add the BUG_ON */ + BUG_ON(!local->ops->ampdu_action); + + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, + ra, tid, NULL); + if (ret) + printk(KERN_DEBUG "HW problem - can not stop rx " + "aggergation for tid %d\n", tid); + + /* shutdown timer has not expired */ + if (initiator != WLAN_BACK_TIMER) + del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]. + session_timer); + + /* check if this is a self generated aggregation halt */ + if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) + ieee80211_send_delba(dev, ra, tid, 0, reason); + + /* free the reordering buffer */ + for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) { + if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) { + /* release the reordered frames */ + dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]); + sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--; + sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL; + } + } + kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); + + sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; + sta_info_put(sta); +} + + +static void ieee80211_sta_process_delba(struct net_device *dev, + struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + u16 tid, params; + u16 initiator; + DECLARE_MAC_BUF(mac); + + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return; + + params = le16_to_cpu(mgmt->u.action.u.delba.params); + tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; + initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; + +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", + print_mac(mac, mgmt->sa), + initiator ? "recipient" : "initiator", tid, + mgmt->u.action.u.delba.reason_code); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + if (initiator == WLAN_BACK_INITIATOR) + ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, + WLAN_BACK_INITIATOR, 0); + else { /* WLAN_BACK_RECIPIENT */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + sta->ampdu_mlme.tid_tx[tid].state = + HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, + WLAN_BACK_RECIPIENT); + } + sta_info_put(sta); +} + +/* + * After sending add Block Ack request we activated a timer until + * add Block Ack response will arrive from the recipient. + * If this timer expires sta_addba_resp_timer_expired will be executed. + */ +void sta_addba_resp_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and both sta_info and TID are needed, so init + * flow in sta_info_add gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u16 tid = *(int *)data; + struct sta_info *temp_sta = container_of((void *)data, + struct sta_info, timer_to_tid[tid]); + + struct ieee80211_local *local = temp_sta->local; + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u8 *state; + + sta = sta_info_get(local, temp_sta->addr); + if (!sta) + return; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID waits for addBA response */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + *state = HT_AGG_STATE_IDLE; + printk(KERN_DEBUG "timer expired on tid %d but we are not " + "expecting addBA response there", tid); + goto timer_expired_exit; + } + + printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); + + /* go through the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, + WLAN_BACK_INITIATOR); + +timer_expired_exit: + sta_info_put(sta); +} + +/* + * After receiving Block Ack Request (BAR) we activated a + * timer after each frame arrives from the originator. + * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. + */ +void sta_rx_agg_session_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and verious sta_info are needed here, so init + * flow in sta_info_add gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u8 *ptid = (u8 *)data; + u8 *timer_to_id = ptid - *ptid; + struct sta_info *sta = container_of(timer_to_id, struct sta_info, + timer_to_tid[0]); + + printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); + ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, + WLAN_BACK_TIMER, + WLAN_REASON_QSTA_TIMEOUT); +} + static void ieee80211_rx_mgmt_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta, @@ -943,37 +1508,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u16 auth_alg, auth_transaction, status_code; + DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_AUTHENTICATE && - sdata->type != IEEE80211_IF_TYPE_IBSS) { + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: authentication frame received from " - MAC_FMT ", but not in authenticate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in authenticate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } - if (sdata->type != IEEE80211_IF_TYPE_IBSS && + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } - if (sdata->type != IEEE80211_IF_TYPE_IBSS && + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown BSSID (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -981,12 +1547,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d " + printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " "transaction=%d status=%d)\n", - dev->name, MAC_ARG(mgmt->sa), auth_alg, + dev->name, print_mac(mac, mgmt->sa), auth_alg, auth_transaction, status_code); - if (sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { /* IEEE 802.11 standard does not require authentication in IBSS * networks and most implementations do not seem to use it. * However, try to reply to authentication attempts if someone @@ -1070,27 +1636,28 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT + printk(KERN_DEBUG "%s: RX deauthentication from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); @@ -1115,27 +1682,28 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT + printk(KERN_DEBUG "%s: RX disassociation from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); @@ -1150,58 +1718,58 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, } -static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, +static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta, struct ieee80211_mgmt *mgmt, size_t len, int reassoc) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; + struct ieee80211_local *local = sdata->local; + struct net_device *dev = sdata->dev; + struct ieee80211_supported_band *sband; struct sta_info *sta; - u32 rates; + u64 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; + struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; u8 *pos; int i, j; + DECLARE_MAC_BUF(mac); + bool have_higher_than_11mbit = false; /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ if (ifsta->state != IEEE80211_ASSOCIATE) { printk(KERN_DEBUG "%s: association frame received from " - MAC_FMT ", but not in associate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in associate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " - "set\n", dev->name, aid); - aid &= ~(BIT(15) | BIT(14)); - printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x " + printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " "status=%d aid=%d)\n", - dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa), - capab_info, status_code, aid); + dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", @@ -1213,13 +1781,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, return; } + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) + printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " + "set\n", dev->name, aid); + aid &= ~(BIT(15) | BIT(14)); + pos = mgmt->u.assoc_resp.variable; - if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) - == ParseFailed) { - printk(KERN_DEBUG "%s: failed to parse AssocResp\n", - dev->name); - return; - } + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", @@ -1227,18 +1795,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, return; } - /* it probably doesn't, but if the frame includes an ERP value then - * update our stored copy */ - if (elems.erp_info && elems.erp_info_len >= 1) { - struct ieee80211_sta_bss *bss - = ieee80211_rx_bss_get(dev, ifsta->bssid); - if (bss) { - bss->erp_value = elems.erp_info[0]; - bss->has_erp_value = 1; - ieee80211_rx_bss_put(dev, bss); - } - } - printk(KERN_DEBUG "%s: associated\n", dev->name); ifsta->aid = aid; ifsta->ap_capab = capab_info; @@ -1249,8 +1805,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); - ieee80211_set_associated(dev, ifsta, 1); - /* Add STA entry for the AP */ sta = sta_info_get(local, ifsta->bssid); if (!sta) { @@ -1261,7 +1815,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, " AP\n", dev->name); return; } - bss = ieee80211_rx_bss_get(dev, ifsta->bssid); + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); if (bss) { sta->last_rssi = bss->rssi; sta->last_signal = bss->signal; @@ -1271,23 +1827,63 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, } sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED; rates = 0; - mode = local->oper_hw_mode; + basic_rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } } + for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.ext_supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } + } + + sta->supp_rates[local->hw.conf.channel->band] = rates; + sdata->basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && + local->ops->conf_ht) { + struct ieee80211_ht_bss_info bss_info; + + ieee80211_ht_cap_ie_to_ht_info( + (struct ieee80211_ht_cap *) + elems.ht_cap_elem, &sta->ht_info); + ieee80211_ht_addt_info_ie_to_ht_bss_info( + (struct ieee80211_ht_addt_info *) + elems.ht_info_elem, &bss_info); + ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info); } - sta->supp_rates = rates; rate_control_rate_init(sta, local); @@ -1297,6 +1893,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, elems.wmm_param_len); } + /* set AID, ieee80211_set_associated() will tell the driver */ + bss_conf->aid = aid; + ieee80211_set_associated(dev, ifsta, 1); sta_info_put(sta); @@ -1337,7 +1936,8 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev, static struct ieee80211_sta_bss * -ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) +ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; @@ -1348,6 +1948,11 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) atomic_inc(&bss->users); atomic_inc(&bss->users); memcpy(bss->bssid, bssid, ETH_ALEN); + bss->freq = freq; + if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { + memcpy(bss->ssid, ssid, ssid_len); + bss->ssid_len = ssid_len; + } spin_lock_bh(&local->sta_bss_lock); /* TODO: order by RSSI? */ @@ -1359,7 +1964,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid) +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; @@ -1367,7 +1973,10 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid) spin_lock_bh(&local->sta_bss_lock); bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + if (!memcmp(bss->bssid, bssid, ETH_ALEN) && + bss->freq == freq && + bss->ssid_len == ssid_len && + (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { atomic_inc(&bss->users); break; } @@ -1383,6 +1992,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->wpa_ie); kfree(bss->rsn_ie); kfree(bss->wmm_ie); + kfree(bss->ht_ie); kfree(bss); } @@ -1429,19 +2039,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee802_11_elems elems; size_t baselen; - int channel, invalid = 0, clen; + int freq, clen; struct ieee80211_sta_bss *bss; struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 timestamp; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ #if 0 - printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n", + printk(KERN_DEBUG "%s: RX %s from %s to %s\n", dev->name, beacon ? "Beacon" : "Probe Response", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da)); + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); #endif baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1450,7 +2062,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); - if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon && + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { #ifdef CONFIG_MAC80211_IBSS_DEBUG static unsigned long last_tsf_debug = 0; @@ -1460,10 +2072,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else tsf = -1LLU; if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID=" - MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld " + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld " "@%lu\n", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid), + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), (unsigned long long)tsf, (unsigned long long)timestamp, (unsigned long long)(tsf - timestamp), @@ -1473,23 +2085,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif /* CONFIG_MAC80211_IBSS_DEBUG */ } - if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, - &elems) == ParseFailed) - invalid = 1; + ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rates; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *bitrates; size_t num_rates; - u32 supp_rates, prev_rates; + u64 supp_rates, prev_rates; int i, j; - mode = local->sta_scanning ? - local->scan_hw_mode : local->oper_hw_mode; - rates = mode->rates; - num_rates = mode->num_rates; + sband = local->hw.wiphy->bands[rx_status->band]; + + if (!sband) { + WARN_ON(1); + sband = local->hw.wiphy->bands[ + local->hw.conf.channel->band]; + } + + bitrates = sband->bitrates; + num_rates = sband->n_bitrates; supp_rates = 0; for (i = 0; i < elems.supp_rates_len + @@ -1503,24 +2119,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev, [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); for (j = 0; j < num_rates; j++) - if (rates[j].rate == own_rate) + if (bitrates[j].bitrate == own_rate) supp_rates |= BIT(j); } - prev_rates = sta->supp_rates; - sta->supp_rates &= supp_rates; - if (sta->supp_rates == 0) { + prev_rates = sta->supp_rates[rx_status->band]; + sta->supp_rates[rx_status->band] &= supp_rates; + if (sta->supp_rates[rx_status->band] == 0) { /* No matching rates - this should not really happen. * Make sure that at least one rate is marked * supported to avoid issues with TX rate ctrl. */ - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->supp_rates[rx_status->band] = + sdata->u.sta.supp_rates_bits[rx_status->band]; } - if (sta->supp_rates != prev_rates) { + if (sta->supp_rates[rx_status->band] != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - MAC_FMT " based on beacon info (0x%x & 0x%x -> " - "0x%x)\n", - dev->name, MAC_ARG(sta->addr), prev_rates, - supp_rates, sta->supp_rates); + "%s based on beacon info (0x%llx & 0x%llx -> " + "0x%llx)\n", + dev->name, print_mac(mac, sta->addr), + (unsigned long long) prev_rates, + (unsigned long long) supp_rates, + (unsigned long long) sta->supp_rates[rx_status->band]); } sta_info_put(sta); } @@ -1529,13 +2148,15 @@ static void ieee80211_rx_bss_info(struct net_device *dev, return; if (elems.ds_params && elems.ds_params_len == 1) - channel = elems.ds_params[0]; + freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else - channel = rx_status->channel; + freq = rx_status->freq; - bss = ieee80211_rx_bss_get(dev, mgmt->bssid); + bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, + elems.ssid, elems.ssid_len); if (!bss) { - bss = ieee80211_rx_bss_add(dev, mgmt->bssid); + bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, + elems.ssid, elems.ssid_len); if (!bss) return; } else { @@ -1547,6 +2168,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } + bss->band = rx_status->band; + if (bss->probe_resp && beacon) { /* Do not allow beacon to override data from Probe Response. */ ieee80211_rx_bss_put(dev, bss); @@ -1561,10 +2184,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); - if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) { - memcpy(bss->ssid, elems.ssid, elems.ssid_len); - bss->ssid_len = elems.ssid_len; - } bss->supp_rates_len = 0; if (elems.supp_rates) { @@ -1632,23 +2251,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->wmm_ie = NULL; bss->wmm_ie_len = 0; } - - - bss->hw_mode = rx_status->phymode; - bss->channel = channel; - bss->freq = rx_status->freq; - if (channel != rx_status->channel && - (bss->hw_mode == MODE_IEEE80211G || - bss->hw_mode == MODE_IEEE80211B) && - channel >= 1 && channel <= 14) { - static const int freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - /* IEEE 802.11g/b mode can receive packets from neighboring - * channels, so map the channel into frequency. */ - bss->freq = freq_list[channel - 1]; + if (elems.ht_cap_elem && + (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || + memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { + kfree(bss->ht_ie); + bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); + if (bss->ht_ie) { + memcpy(bss->ht_ie, elems.ht_cap_elem - 2, + elems.ht_cap_elem_len + 2); + bss->ht_ie_len = elems.ht_cap_elem_len + 2; + } else + bss->ht_ie_len = 0; + } else if (!elems.ht_cap_elem && bss->ht_ie) { + kfree(bss->ht_ie); + bss->ht_ie = NULL; + bss->ht_ie_len = 0; } + bss->timestamp = timestamp; bss->last_update = jiffies; bss->rssi = rx_status->ssi; @@ -1678,11 +2297,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, struct ieee80211_if_sta *ifsta; size_t baselen; struct ieee802_11_elems elems; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + u32 changed = 0; ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type != IEEE80211_IF_TYPE_STA) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return; ifsta = &sdata->u.sta; @@ -1695,17 +2317,34 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, if (baselen > len) return; - if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, - &elems) == ParseFailed) - return; + ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); if (elems.erp_info && elems.erp_info_len >= 1) - ieee80211_handle_erp_ie(dev, elems.erp_info[0]); + changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); + + if (elems.ht_cap_elem && elems.ht_info_elem && + elems.wmm_param && local->ops->conf_ht && + conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + struct ieee80211_ht_bss_info bss_info; + + ieee80211_ht_addt_info_ie_to_ht_bss_info( + (struct ieee80211_ht_addt_info *) + elems.ht_info_elem, &bss_info); + /* check if AP changed bss inforamation */ + if ((conf->ht_bss_conf.primary_channel != + bss_info.primary_channel) || + (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) || + (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode)) + ieee80211_hw_config_ht(local, 1, &conf->ht_conf, + &bss_info); + } if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); } + + ieee80211_bss_info_change_notify(sdata, changed); } @@ -1721,8 +2360,13 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; + DECLARE_MAC_BUF(mac); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); +#endif - if (sdata->type != IEEE80211_IF_TYPE_IBSS || + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS || ifsta->state != IEEE80211_IBSS_JOINED || len < 24 + 2 || !ifsta->probe_resp) return; @@ -1733,10 +2377,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, tx_last_beacon = 1; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID=" - MAC_FMT " (tx_last_beacon=%d)\n", - dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da), - MAC_ARG(mgmt->bssid), tx_last_beacon); + printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" + "%s (tx_last_beacon=%d)\n", + dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), + print_mac(mac3, mgmt->bssid), tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) @@ -1752,8 +2396,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, pos + 2 + pos[1] > end) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from " MAC_FMT "\n", - dev->name, MAC_ARG(mgmt->sa)); + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); } return; } @@ -1772,12 +2416,52 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n", - dev->name, MAC_ARG(resp->da)); + printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", + dev->name, print_mac(mac, resp->da)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_tx(dev, skb, 0); } +static void ieee80211_rx_mgmt_action(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + if (len < IEEE80211_MIN_ACTION_SIZE) + return; + + switch (mgmt->u.action.category) { + case WLAN_CATEGORY_BACK: + switch (mgmt->u.action.u.addba_req.action_code) { + case WLAN_ACTION_ADDBA_REQ: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_req))) + break; + ieee80211_sta_process_addba_request(dev, mgmt, len); + break; + case WLAN_ACTION_ADDBA_RESP: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_resp))) + break; + ieee80211_sta_process_addba_resp(dev, mgmt, len); + break; + case WLAN_ACTION_DELBA: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.delba))) + break; + ieee80211_sta_process_delba(dev, mgmt, len); + break; + default: + if (net_ratelimit()) + printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n", + dev->name); + break; + } + break; + default: + break; + } +} void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) @@ -1807,6 +2491,7 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: + case IEEE80211_STYPE_ACTION: skb_queue_tail(&ifsta->skb_queue, skb); queue_work(local->hw.workqueue, &ifsta->work); return; @@ -1853,10 +2538,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len); break; case IEEE80211_STYPE_ASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0); + ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); break; case IEEE80211_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1); + ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); break; case IEEE80211_STYPE_DEAUTH: ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len); @@ -1864,37 +2549,48 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, case IEEE80211_STYPE_DISASSOC: ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); break; + case IEEE80211_STYPE_ACTION: + ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len); + break; } kfree_skb(skb); } -void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_rx_result +ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) { struct ieee80211_mgmt *mgmt; u16 fc; - if (skb->len < 24) { - dev_kfree_skb(skb); - return; - } + if (skb->len < 2) + return RX_DROP_UNUSABLE; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) + return RX_CONTINUE; + + if (skb->len < 24) + return RX_DROP_MONITOR; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; } } - - dev_kfree_skb(skb); + return RX_CONTINUE; } @@ -1924,13 +2620,14 @@ static void ieee80211_sta_expire(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); + DECLARE_MAC_BUF(mac); write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { - printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT - "\n", dev->name, MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: expiring inactive STA %s\n", + dev->name, print_mac(mac, sta->addr)); __sta_info_get(sta); sta_info_remove(sta); list_add(&sta->list, &tmp_list); @@ -1983,13 +2680,13 @@ void ieee80211_sta_work(struct work_struct *work) if (!netif_running(dev)) return; - if (local->sta_scanning) + if (local->sta_sw_scanning || local->sta_hw_scanning) return; - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " - "(type=%d)\n", dev->name, sdata->type); + "(type=%d)\n", dev->name, sdata->vif.type); return; } ifsta = &sdata->u.sta; @@ -2000,7 +2697,10 @@ void ieee80211_sta_work(struct work_struct *work) if (ifsta->state != IEEE80211_AUTHENTICATE && ifsta->state != IEEE80211_ASSOCIATE && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { - ieee80211_sta_start_scan(dev, NULL, 0); + if (ifsta->scan_ssid_len) + ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len); + else + ieee80211_sta_start_scan(dev, NULL, 0); return; } @@ -2081,7 +2781,7 @@ void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type != IEEE80211_IF_TYPE_STA) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return; if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | @@ -2098,7 +2798,8 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, { int tmp, hidden_ssid; - if (!memcmp(ifsta->ssid, ssid, ssid_len)) + if (ssid_len == ifsta->ssid_len && + !memcmp(ifsta->ssid, ssid, ssid_len)) return 1; if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) @@ -2138,7 +2839,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, } spin_lock_bh(&local->sta_bss_lock); - freq = local->oper_channel->freq; + freq = local->oper_channel->center_freq; list_for_each_entry(bss, &local->sta_bss_list, list) { if (!(bss->capability & WLAN_CAPABILITY_ESS)) continue; @@ -2169,7 +2870,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); if (selected) { - ieee80211_set_channel(local, -1, selected->freq); + ieee80211_set_freq(local, selected->freq); if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); @@ -2202,11 +2903,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; struct ieee80211_tx_control control; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode; - struct rate_control_extra extra; + struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; /* Remove possible STA entries from other IBSS networks. */ sta_info_flush(local, NULL); @@ -2226,12 +2928,11 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, sdata->drop_unencrypted = bss->capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - res = ieee80211_set_channel(local, -1, bss->freq); + res = ieee80211_set_freq(local, bss->freq); - if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) { - printk(KERN_DEBUG "%s: IBSS not allowed on channel %d " - "(%d MHz)\n", dev->name, local->hw.conf.channel, - local->hw.conf.freq); + if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, local->oper_channel->center_freq); return -1; } @@ -2268,10 +2969,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, *pos++ = rates; memcpy(pos, bss->supp_rates, rates); - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = bss->channel; + if (bss->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(bss->freq); + } pos = skb_put(skb, 2 + 2); *pos++ = WLAN_EID_IBSS_PARAMS; @@ -2289,20 +2992,18 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } memset(&control, 0, sizeof(control)); - memset(&extra, 0, sizeof(extra)); - extra.mode = local->oper_hw_mode; - rate = rate_control_get_rate(local, dev, skb, &extra); - if (!rate) { + rate_control_get_rate(dev, sband, skb, &ratesel); + if (!ratesel.rate) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } - control.tx_rate = - ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rate->val2 : rate->val; + control.vif = &sdata->vif; + control.tx_rate = ratesel.rate; + if (sdata->bss_conf.use_short_preamble && + ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.power_level = local->hw.conf.power_level; control.flags |= IEEE80211_TXCTL_NO_ACK; control.retry_limit = 1; @@ -2327,14 +3028,14 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } rates = 0; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < bss->supp_rates_len; i++) { int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == bitrate) + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) rates |= BIT(j); } - ifsta->supp_rates_bits = rates; + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; } while (0); if (skb) { @@ -2357,10 +3058,11 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN], *pos; int i; + DECLARE_MAC_BUF(mac); #if 0 /* Easier testing, use fixed BSSID. */ @@ -2376,32 +3078,31 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, bssid[0] |= 0x02; #endif - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n", - dev->name, MAC_ARG(bssid)); + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", + dev->name, print_mac(mac, bssid)); - bss = ieee80211_rx_bss_add(dev, bssid); + bss = ieee80211_rx_bss_add(dev, bssid, + local->hw.conf.channel->center_freq, + sdata->u.sta.ssid, sdata->u.sta.ssid_len); if (!bss) return -ENOMEM; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - mode = local->oper_hw_mode; + bss->band = local->hw.conf.channel->band; + sband = local->hw.wiphy->bands[bss->band]; if (local->hw.conf.beacon_int == 0) local->hw.conf.beacon_int = 100; bss->beacon_int = local->hw.conf.beacon_int; - bss->hw_mode = local->hw.conf.phymode; - bss->channel = local->hw.conf.channel; - bss->freq = local->hw.conf.freq; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; if (sdata->default_key) { bss->capability |= WLAN_CAPABILITY_PRIVACY; } else sdata->drop_unencrypted = 0; - bss->supp_rates_len = mode->num_rates; + bss->supp_rates_len = sband->n_bitrates; pos = bss->supp_rates; - for (i = 0; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } @@ -2417,6 +3118,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int found = 0; u8 bssid[ETH_ALEN]; int active_ibss; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (ifsta->ssid_len == 0) return -EINVAL; @@ -2433,8 +3136,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, || !(bss->capability & WLAN_CAPABILITY_IBSS)) continue; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=" MAC_FMT " found\n", - MAC_ARG(bss->bssid)); + printk(KERN_DEBUG " bssid=%s found\n", + print_mac(mac, bss->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ memcpy(bssid, bss->bssid, ETH_ALEN); found = 1; @@ -2444,14 +3147,16 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected " MAC_FMT " current " - MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG " sta_find_ibss: selected %s current " + "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT + (bss = ieee80211_rx_bss_get(dev, bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len))) { + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", - dev->name, MAC_ARG(bssid)); + dev->name, print_mac(mac, bssid)); return ieee80211_sta_join_ibss(dev, ifsta, bss); } #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -2475,13 +3180,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, if (time_after(jiffies, ifsta->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && - local->oper_channel->flag & IEEE80211_CHAN_W_IBSS) + (!(local->oper_channel->flags & + IEEE80211_CHAN_NO_IBSS))) return ieee80211_sta_create_ibss(dev, ifsta); if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on the" - " configured channel %d (%d MHz)\n", - dev->name, local->hw.conf.channel, - local->hw.conf.freq); + printk(KERN_DEBUG "%s: IBSS not allowed on" + " %d MHz\n", dev->name, + local->hw.conf.channel->center_freq); } /* No IBSS found - decrease scan interval and continue @@ -2500,7 +3205,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -2514,18 +3219,23 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) int i; memset(&qparam, 0, sizeof(qparam)); - /* TODO: are these ok defaults for all hw_modes? */ + qparam.aifs = 2; - qparam.cw_min = - local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) + qparam.cw_min = 31; + else + qparam.cw_min = 15; + qparam.cw_max = 1023; qparam.burst_time = 0; + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - { local->ops->conf_tx(local_to_hw(local), i + IEEE80211_TX_QUEUE_DATA0, &qparam); - } + /* IBSS uses different parameters for Beacon sending */ qparam.cw_min++; qparam.cw_min *= 2; @@ -2534,7 +3244,6 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) IEEE80211_TX_QUEUE_BEACON, &qparam); } - sdata = IEEE80211_DEV_TO_SUB_IF(dev); ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) @@ -2547,7 +3256,7 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) ifsta->flags |= IEEE80211_STA_SSID_SET; else ifsta->flags &= ~IEEE80211_STA_SSID_SET; - if (sdata->type == IEEE80211_IF_TYPE_IBSS && + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { ifsta->ibss_join_req = jiffies; ifsta->state = IEEE80211_IBSS_SEARCH; @@ -2634,11 +3343,17 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) union iwreq_data wrqu; local->last_scan_completed = jiffies; - wmb(); - local->sta_scanning = 0; + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + if (local->sta_hw_scanning) { + local->sta_hw_scanning = 0; + goto done; + } + + local->sta_sw_scanning = 0; if (ieee80211_hw_config(local)) - printk(KERN_DEBUG "%s: failed to restore operational" + printk(KERN_DEBUG "%s: failed to restore operational " "channel after scan\n", dev->name); @@ -2652,9 +3367,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) netif_tx_unlock_bh(local->mdev); - memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { @@ -2662,7 +3374,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (sdata->dev == local->mdev) continue; - if (sdata->type == IEEE80211_IF_TYPE_STA) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) ieee80211_send_nullfunc(local, sdata, 0); ieee80211_sta_timer((unsigned long)sdata); @@ -2672,8 +3384,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) } rcu_read_unlock(); +done: sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || (!ifsta->state == IEEE80211_IBSS_JOINED && @@ -2689,54 +3402,69 @@ void ieee80211_sta_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct net_device *dev = local->scan_dev; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; int skip; unsigned long next_delay = 0; - if (!local->sta_scanning) + if (!local->sta_sw_scanning) return; switch (local->scan_state) { case SCAN_SET_CHANNEL: - mode = local->scan_hw_mode; - if (local->scan_hw_mode->list.next == &local->modes_list && - local->scan_channel_idx >= mode->num_channels) { + /* + * Get current scan band. scan_band may be IEEE80211_NUM_BANDS + * after we successfully scanned the last channel of the last + * band (and the last band is supported by the hw) + */ + if (local->scan_band < IEEE80211_NUM_BANDS) + sband = local->hw.wiphy->bands[local->scan_band]; + else + sband = NULL; + + /* + * If we are at an unsupported band and have more bands + * left to scan, advance to the next supported one. + */ + while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { + local->scan_band++; + sband = local->hw.wiphy->bands[local->scan_band]; + local->scan_channel_idx = 0; + } + + /* if no more bands/channels left, complete scan */ + if (!sband || local->scan_channel_idx >= sband->n_channels) { ieee80211_scan_completed(local_to_hw(local)); return; } - skip = !(local->enabled_modes & (1 << mode->mode)); - chan = &mode->channels[local->scan_channel_idx]; - if (!(chan->flag & IEEE80211_CHAN_W_SCAN) || - (sdata->type == IEEE80211_IF_TYPE_IBSS && - !(chan->flag & IEEE80211_CHAN_W_IBSS)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + skip = 0; + chan = &sband->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || + (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + chan->flags & IEEE80211_CHAN_NO_IBSS)) skip = 1; if (!skip) { -#if 0 - printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n", - dev->name, chan->chan, chan->freq); -#endif - local->scan_channel = chan; if (ieee80211_hw_config(local)) { - printk(KERN_DEBUG "%s: failed to set channel " - "%d (%d MHz) for scan\n", dev->name, - chan->chan, chan->freq); + printk(KERN_DEBUG "%s: failed to set freq to " + "%d MHz for scan\n", dev->name, + chan->center_freq); skip = 1; } } + /* advance state machine to next channel/band */ local->scan_channel_idx++; - if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) { - if (local->scan_hw_mode->list.next != &local->modes_list) { - local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next, - struct ieee80211_hw_mode, - list); - local->scan_channel_idx = 0; - } + if (local->scan_channel_idx >= sband->n_channels) { + /* + * scan_band may end up == IEEE80211_NUM_BANDS, but + * we'll catch that case above and complete the scan + * if that is the case. + */ + local->scan_band++; + local->scan_channel_idx = 0; } if (skip) @@ -2747,17 +3475,18 @@ void ieee80211_sta_scan_work(struct work_struct *work) local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) { - ieee80211_send_probe_req(dev, NULL, local->scan_ssid, - local->scan_ssid_len); - next_delay = IEEE80211_CHANNEL_TIME; - } else - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->scan_state = SCAN_SET_CHANNEL; + + if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) + break; + ieee80211_send_probe_req(dev, NULL, local->scan_ssid, + local->scan_ssid_len); + next_delay = IEEE80211_CHANNEL_TIME; break; } - if (local->sta_scanning) + if (local->sta_sw_scanning) queue_delayed_work(local->hw.workqueue, &local->scan_work, next_delay); } @@ -2789,7 +3518,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, * ResultCode: SUCCESS, INVALID_PARAMETERS */ - if (local->sta_scanning) { + if (local->sta_sw_scanning || local->sta_hw_scanning) { if (local->scan_dev == dev) return 0; return -EBUSY; @@ -2797,15 +3526,15 @@ static int ieee80211_sta_start_scan(struct net_device *dev, if (local->ops->hw_scan) { int rc = local->ops->hw_scan(local_to_hw(local), - ssid, ssid_len); + ssid, ssid_len); if (!rc) { - local->sta_scanning = 1; + local->sta_hw_scanning = 1; local->scan_dev = dev; } return rc; } - local->sta_scanning = 1; + local->sta_sw_scanning = 1; rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { @@ -2816,7 +3545,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, continue; netif_stop_queue(sdata->dev); - if (sdata->type == IEEE80211_IF_TYPE_STA && + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) ieee80211_send_nullfunc(local, sdata, 1); } @@ -2828,10 +3557,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, } else local->scan_ssid_len = 0; local->scan_state = SCAN_SET_CHANNEL; - local->scan_hw_mode = list_entry(local->modes_list.next, - struct ieee80211_hw_mode, - list); local->scan_channel_idx = 0; + local->scan_band = IEEE80211_BAND_2GHZ; local->scan_dev = dev; netif_tx_lock_bh(local->mdev); @@ -2857,15 +3584,18 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) struct ieee80211_if_sta *ifsta = &sdata->u.sta; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (sdata->type != IEEE80211_IF_TYPE_STA) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return ieee80211_sta_start_scan(dev, ssid, ssid_len); - if (local->sta_scanning) { + if (local->sta_sw_scanning || local->sta_hw_scanning) { if (local->scan_dev == dev) return 0; return -EBUSY; } + ifsta->scan_ssid_len = ssid_len; + if (ssid_len) + memcpy(ifsta->scan_ssid, ssid, ssid_len); set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); queue_work(local->hw.workqueue, &ifsta->work); return 0; @@ -2883,18 +3613,6 @@ ieee80211_sta_scan_result(struct net_device *dev, bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) return current_ev; - if (!(local->enabled_modes & (1 << bss->hw_mode))) - return current_ev; - - if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY && - !bss->wpa_ie && !bss->rsn_ie) - return current_ev; - - if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID && - (local->scan_ssid_len != bss->ssid_len || - memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0)) - return current_ev; - memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -2922,12 +3640,15 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = bss->channel; - iwe.u.freq.e = 0; + iwe.u.freq.m = bss->freq; + iwe.u.freq.e = 6; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); - iwe.u.freq.m = bss->freq * 100000; - iwe.u.freq.e = 1; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); + iwe.u.freq.e = 0; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); @@ -2998,34 +3719,6 @@ ieee80211_sta_scan_result(struct net_device *dev, } } - do { - char *buf; - - if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO)) - break; - - buf = kmalloc(100, GFP_ATOMIC); - if (!buf) - break; - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", bss->beacon_int); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - buf); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "capab=0x%04x", bss->capability); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - buf); - - kfree(buf); - break; - } while (0); - return current_ev; } @@ -3079,25 +3772,29 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr)); + "entry %s\n", dev->name, print_mac(mac, addr)); } return NULL; } - printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n", - wiphy_name(local->hw.wiphy), MAC_ARG(addr), dev->name); + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", + wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); if (!sta) return NULL; - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->flags |= WLAN_STA_AUTHORIZED; + + sta->supp_rates[local->hw.conf.channel->band] = + sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; rate_control_rate_init(sta, local); @@ -3113,8 +3810,8 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason) printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n", dev->name, reason); - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) return -EINVAL; ieee80211_send_deauth(dev, ifsta, reason); @@ -3131,7 +3828,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) printk(KERN_DEBUG "%s: disassociate(reason=%d)\n", dev->name, reason); - if (sdata->type != IEEE80211_IF_TYPE_STA) + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return -EINVAL; if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) diff --git a/package/mac80211/src/net/mac80211/key.c b/package/mac80211/src/net/mac80211/key.c index d9ab0871fe..ed57fb8e82 100644 --- a/package/mac80211/src/net/mac80211/key.c +++ b/package/mac80211/src/net/mac80211/key.c @@ -49,8 +49,8 @@ static const u8 *get_mac_for_key(struct ieee80211_key *key) * address to indicate a transmit-only key. */ if (key->conf.alg != ALG_WEP && - (key->sdata->type == IEEE80211_IF_TYPE_AP || - key->sdata->type == IEEE80211_IF_TYPE_VLAN)) + (key->sdata->vif.type == IEEE80211_IF_TYPE_AP || + key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) addr = zero_addr; if (key->sta) @@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " - "(%d, " MAC_FMT ") to hardware (%d)\n", + "(%d, %s) to hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); } static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " - "(%d, " MAC_FMT ") from hardware (%d)\n", + "(%d, %s) from hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } @@ -170,7 +172,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, if (sta->flags & WLAN_STA_WME) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; } else { - if (sdata->type == IEEE80211_IF_TYPE_STA) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { struct sta_info *ap; /* same here, the AP could be using QoS */ diff --git a/package/mac80211/src/net/mac80211/rc80211_pid.h b/package/mac80211/src/net/mac80211/rc80211_pid.h new file mode 100644 index 0000000000..04afc13ed8 --- /dev/null +++ b/package/mac80211/src/net/mac80211/rc80211_pid.h @@ -0,0 +1,285 @@ +/* + * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> + * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RC80211_PID_H +#define RC80211_PID_H + +/* Sampling period for measuring percentage of failed frames in ms. */ +#define RC_PID_INTERVAL 125 + +/* Exponential averaging smoothness (used for I part of PID controller) */ +#define RC_PID_SMOOTHING_SHIFT 3 +#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) + +/* Sharpening factor (used for D part of PID controller) */ +#define RC_PID_SHARPENING_FACTOR 0 +#define RC_PID_SHARPENING_DURATION 0 + +/* Fixed point arithmetic shifting amount. */ +#define RC_PID_ARITH_SHIFT 8 + +/* Fixed point arithmetic factor. */ +#define RC_PID_ARITH_FACTOR (1 << RC_PID_ARITH_SHIFT) + +/* Proportional PID component coefficient. */ +#define RC_PID_COEFF_P 15 +/* Integral PID component coefficient. */ +#define RC_PID_COEFF_I 9 +/* Derivative PID component coefficient. */ +#define RC_PID_COEFF_D 15 + +/* Target failed frames rate for the PID controller. NB: This effectively gives + * maximum failed frames percentage we're willing to accept. If the wireless + * link quality is good, the controller will fail to adjust failed frames + * percentage to the target. This is intentional. + */ +#define RC_PID_TARGET_PF 14 + +/* Rate behaviour normalization quantity over time. */ +#define RC_PID_NORM_OFFSET 3 + +/* Push high rates right after loading. */ +#define RC_PID_FAST_START 0 + +/* Arithmetic right shift for positive and negative values for ISO C. */ +#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \ + (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y) + +enum rc_pid_event_type { + RC_PID_EVENT_TYPE_TX_STATUS, + RC_PID_EVENT_TYPE_RATE_CHANGE, + RC_PID_EVENT_TYPE_TX_RATE, + RC_PID_EVENT_TYPE_PF_SAMPLE, +}; + +union rc_pid_event_data { + /* RC_PID_EVENT_TX_STATUS */ + struct { + struct ieee80211_tx_status tx_status; + }; + /* RC_PID_EVENT_TYPE_RATE_CHANGE */ + /* RC_PID_EVENT_TYPE_TX_RATE */ + struct { + int index; + int rate; + }; + /* RC_PID_EVENT_TYPE_PF_SAMPLE */ + struct { + s32 pf_sample; + s32 prop_err; + s32 int_err; + s32 der_err; + }; +}; + +struct rc_pid_event { + /* The time when the event occured */ + unsigned long timestamp; + + /* Event ID number */ + unsigned int id; + + /* Type of event */ + enum rc_pid_event_type type; + + /* type specific data */ + union rc_pid_event_data data; +}; + +/* Size of the event ring buffer. */ +#define RC_PID_EVENT_RING_SIZE 32 + +struct rc_pid_event_buffer { + /* Counter that generates event IDs */ + unsigned int ev_count; + + /* Ring buffer of events */ + struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE]; + + /* Index to the entry in events_buf to be reused */ + unsigned int next_entry; + + /* Lock that guards against concurrent access to this buffer struct */ + spinlock_t lock; + + /* Wait queue for poll/select and blocking I/O */ + wait_queue_head_t waitqueue; +}; + +struct rc_pid_events_file_info { + /* The event buffer we read */ + struct rc_pid_event_buffer *events; + + /* The entry we have should read next */ + unsigned int next_entry; +}; + +/** + * struct rc_pid_debugfs_entries - tunable parameters + * + * Algorithm parameters, tunable via debugfs. + * @dir: the debugfs directory for a specific phy + * @target: target percentage for failed frames + * @sampling_period: error sampling interval in milliseconds + * @coeff_p: absolute value of the proportional coefficient + * @coeff_i: absolute value of the integral coefficient + * @coeff_d: absolute value of the derivative coefficient + * @smoothing_shift: absolute value of the integral smoothing factor (i.e. + * amount of smoothing introduced by the exponential moving average) + * @sharpen_factor: absolute value of the derivative sharpening factor (i.e. + * amount of emphasis given to the derivative term after low activity + * events) + * @sharpen_duration: duration of the sharpening effect after the detected low + * activity event, relative to sampling_period + * @norm_offset: amount of normalization periodically performed on the learnt + * rate behaviour values (lower means we should trust more what we learnt + * about behaviour of rates, higher means we should trust more the natural + * ordering of rates) + * @fast_start: if Y, push high rates right after initialization + */ +struct rc_pid_debugfs_entries { + struct dentry *dir; + struct dentry *target; + struct dentry *sampling_period; + struct dentry *coeff_p; + struct dentry *coeff_i; + struct dentry *coeff_d; + struct dentry *smoothing_shift; + struct dentry *sharpen_factor; + struct dentry *sharpen_duration; + struct dentry *norm_offset; + struct dentry *fast_start; +}; + +void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, + struct ieee80211_tx_status *stat); + +void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, + int index, int rate); + +void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, + int index, int rate); + +void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, + s32 pf_sample, s32 prop_err, + s32 int_err, s32 der_err); + +void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, + struct dentry *dir); + +void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta); + +struct rc_pid_sta_info { + unsigned long last_change; + unsigned long last_sample; + + u32 tx_num_failed; + u32 tx_num_xmit; + + /* Average failed frames percentage error (i.e. actual vs. target + * percentage), scaled by RC_PID_SMOOTHING. This value is computed + * using using an exponential weighted average technique: + * + * (RC_PID_SMOOTHING - 1) * err_avg_old + err + * err_avg = ------------------------------------------ + * RC_PID_SMOOTHING + * + * where err_avg is the new approximation, err_avg_old the previous one + * and err is the error w.r.t. to the current failed frames percentage + * sample. Note that the bigger RC_PID_SMOOTHING the more weight is + * given to the previous estimate, resulting in smoother behavior (i.e. + * corresponding to a longer integration window). + * + * For computation, we actually don't use the above formula, but this + * one: + * + * err_avg_scaled = err_avg_old_scaled - err_avg_old + err + * + * where: + * err_avg_scaled = err * RC_PID_SMOOTHING + * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING + * + * This avoids floating point numbers and the per_failed_old value can + * easily be obtained by shifting per_failed_old_scaled right by + * RC_PID_SMOOTHING_SHIFT. + */ + s32 err_avg_sc; + + /* Last framed failes percentage sample. */ + u32 last_pf; + + /* Sharpening needed. */ + u8 sharp_cnt; + +#ifdef CONFIG_MAC80211_DEBUGFS + /* Event buffer */ + struct rc_pid_event_buffer events; + + /* Events debugfs file entry */ + struct dentry *events_entry; +#endif +}; + +/* Algorithm parameters. We keep them on a per-algorithm approach, so they can + * be tuned individually for each interface. + */ +struct rc_pid_rateinfo { + + /* Map sorted rates to rates in ieee80211_hw_mode. */ + int index; + + /* Map rates in ieee80211_hw_mode to sorted rates. */ + int rev_index; + + /* Did we do any measurement on this rate? */ + bool valid; + + /* Comparison with the lowest rate. */ + int diff; +}; + +struct rc_pid_info { + + /* The failed frames percentage target. */ + unsigned int target; + + /* Rate at which failed frames percentage is sampled in 0.001s. */ + unsigned int sampling_period; + + /* P, I and D coefficients. */ + int coeff_p; + int coeff_i; + int coeff_d; + + /* Exponential averaging shift. */ + unsigned int smoothing_shift; + + /* Sharpening factor and duration. */ + unsigned int sharpen_factor; + unsigned int sharpen_duration; + + /* Normalization offset. */ + unsigned int norm_offset; + + /* Fast starst parameter. */ + unsigned int fast_start; + + /* Rates information. */ + struct rc_pid_rateinfo *rinfo; + + /* Index of the last used rate. */ + int oldrate; + +#ifdef CONFIG_MAC80211_DEBUGFS + /* Debugfs entries created for the parameters above. */ + struct rc_pid_debugfs_entries dentries; +#endif +}; + +#endif /* RC80211_PID_H */ diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_algo.c b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c new file mode 100644 index 0000000000..da8462bbd5 --- /dev/null +++ b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c @@ -0,0 +1,550 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> + * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/debugfs.h> +#include <net/mac80211.h> +#include "ieee80211_rate.h" + +#include "rc80211_pid.h" + + +/* This is an implementation of a TX rate control algorithm that uses a PID + * controller. Given a target failed frames rate, the controller decides about + * TX rate changes to meet the target failed frames rate. + * + * The controller basically computes the following: + * + * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) + * + * where + * adj adjustment value that is used to switch TX rate (see below) + * err current error: target vs. current failed frames percentage + * last_err last error + * err_avg average (i.e. poor man's integral) of recent errors + * sharpening non-zero when fast response is needed (i.e. right after + * association or no frames sent for a long time), heading + * to zero over time + * CP Proportional coefficient + * CI Integral coefficient + * CD Derivative coefficient + * + * CP, CI, CD are subject to careful tuning. + * + * The integral component uses a exponential moving average approach instead of + * an actual sliding window. The advantage is that we don't need to keep an + * array of the last N error values and computation is easier. + * + * Once we have the adj value, we map it to a rate by means of a learning + * algorithm. This algorithm keeps the state of the percentual failed frames + * difference between rates. The behaviour of the lowest available rate is kept + * as a reference value, and every time we switch between two rates, we compute + * the difference between the failed frames each rate exhibited. By doing so, + * we compare behaviours which different rates exhibited in adjacent timeslices, + * thus the comparison is minimally affected by external conditions. This + * difference gets propagated to the whole set of measurements, so that the + * reference is always the same. Periodically, we normalize this set so that + * recent events weigh the most. By comparing the adj value with this set, we + * avoid pejorative switches to lower rates and allow for switches to higher + * rates if they behaved well. + * + * Note that for the computations we use a fixed-point representation to avoid + * floating point arithmetic. Hence, all values are shifted left by + * RC_PID_ARITH_SHIFT. + */ + + +/* Adjust the rate while ensuring that we won't switch to a lower rate if it + * exhibited a worse failed frames behaviour and we'll choose the highest rate + * whose failed frames behaviour is not worse than the one of the original rate + * target. While at it, check that the new rate is valid. */ +static void rate_control_pid_adjust_rate(struct ieee80211_local *local, + struct sta_info *sta, int adj, + struct rc_pid_rateinfo *rinfo) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; + int cur = sta->txrate_idx; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + band = sband->band; + n_bitrates = sband->n_bitrates; + + /* Map passed arguments to sorted values. */ + cur_sorted = rinfo[cur].rev_index; + new_sorted = cur_sorted + adj; + + /* Check limits. */ + if (new_sorted < 0) + new_sorted = rinfo[0].rev_index; + else if (new_sorted >= n_bitrates) + new_sorted = rinfo[n_bitrates - 1].rev_index; + + tmp = new_sorted; + + if (adj < 0) { + /* Ensure that the rate decrease isn't disadvantageous. */ + for (probe = cur_sorted; probe >= new_sorted; probe--) + if (rinfo[probe].diff <= rinfo[cur_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; + } else { + /* Look for rate increase with zero (or below) cost. */ + for (probe = new_sorted + 1; probe < n_bitrates; probe++) + if (rinfo[probe].diff <= rinfo[new_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; + } + + /* Fit the rate found to the nearest supported rate. */ + do { + if (rate_supported(sta, band, rinfo[tmp].index)) { + sta->txrate_idx = rinfo[tmp].index; + break; + } + if (adj < 0) + tmp--; + else + tmp++; + } while (tmp < n_bitrates && tmp >= 0); + +#ifdef CONFIG_MAC80211_DEBUGFS + rate_control_pid_event_rate_change( + &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events, + sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate); +#endif +} + +/* Normalize the failed frames per-rate differences. */ +static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l) +{ + int i, norm_offset = pinfo->norm_offset; + struct rc_pid_rateinfo *r = pinfo->rinfo; + + if (r[0].diff > norm_offset) + r[0].diff -= norm_offset; + else if (r[0].diff < -norm_offset) + r[0].diff += norm_offset; + for (i = 0; i < l - 1; i++) + if (r[i + 1].diff > r[i].diff + norm_offset) + r[i + 1].diff -= norm_offset; + else if (r[i + 1].diff <= r[i].diff) + r[i + 1].diff += norm_offset; +} + +static void rate_control_pid_sample(struct rc_pid_info *pinfo, + struct ieee80211_local *local, + struct sta_info *sta) +{ + struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; + struct rc_pid_rateinfo *rinfo = pinfo->rinfo; + struct ieee80211_supported_band *sband; + u32 pf; + s32 err_avg; + u32 err_prop; + u32 err_int; + u32 err_der; + int adj, i, j, tmp; + unsigned long period; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + spinfo = sta->rate_ctrl_priv; + + /* In case nothing happened during the previous control interval, turn + * the sharpening factor on. */ + period = (HZ * pinfo->sampling_period + 500) / 1000; + if (!period) + period = 1; + if (jiffies - spinfo->last_sample > 2 * period) + spinfo->sharp_cnt = pinfo->sharpen_duration; + + spinfo->last_sample = jiffies; + + /* This should never happen, but in case, we assume the old sample is + * still a good measurement and copy it. */ + if (unlikely(spinfo->tx_num_xmit == 0)) + pf = spinfo->last_pf; + else { + pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; + pf <<= RC_PID_ARITH_SHIFT; + } + + spinfo->tx_num_xmit = 0; + spinfo->tx_num_failed = 0; + + /* If we just switched rate, update the rate behaviour info. */ + if (pinfo->oldrate != sta->txrate_idx) { + + i = rinfo[pinfo->oldrate].rev_index; + j = rinfo[sta->txrate_idx].rev_index; + + tmp = (pf - spinfo->last_pf); + tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); + + rinfo[j].diff = rinfo[i].diff + tmp; + pinfo->oldrate = sta->txrate_idx; + } + rate_control_pid_normalize(pinfo, sband->n_bitrates); + + /* Compute the proportional, integral and derivative errors. */ + err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf; + + err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; + spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; + err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; + + err_der = (pf - spinfo->last_pf) * + (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); + spinfo->last_pf = pf; + if (spinfo->sharp_cnt) + spinfo->sharp_cnt--; + +#ifdef CONFIG_MAC80211_DEBUGFS + rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int, + err_der); +#endif + + /* Compute the controller output. */ + adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i + + err_der * pinfo->coeff_d); + adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT); + + /* Change rate. */ + if (adj) + rate_control_pid_adjust_rate(local, sta, adj, rinfo); +} + +static void rate_control_pid_tx_status(void *priv, struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sub_if_data *sdata; + struct rc_pid_info *pinfo = priv; + struct sta_info *sta; + struct rc_pid_sta_info *spinfo; + unsigned long period; + struct ieee80211_supported_band *sband; + + sta = sta_info_get(local, hdr->addr1); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + if (!sta) + return; + + /* Don't update the state if we're not controlling the rate. */ + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { + sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; + return; + } + + /* Ignore all frames that were sent with a different rate than the rate + * we currently advise mac80211 to use. */ + if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + goto ignore; + + spinfo = sta->rate_ctrl_priv; + spinfo->tx_num_xmit++; + +#ifdef CONFIG_MAC80211_DEBUGFS + rate_control_pid_event_tx_status(&spinfo->events, status); +#endif + + /* We count frames that totally failed to be transmitted as two bad + * frames, those that made it out but had some retries as one good and + * one bad frame. */ + if (status->excessive_retries) { + spinfo->tx_num_failed += 2; + spinfo->tx_num_xmit++; + } else if (status->retry_count) { + spinfo->tx_num_failed++; + spinfo->tx_num_xmit++; + } + + if (status->excessive_retries) { + sta->tx_retry_failed++; + sta->tx_num_consecutive_failures++; + sta->tx_num_mpdu_fail++; + } else { + sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; + sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; + sta->last_ack_rssi[2] = status->ack_signal; + sta->tx_num_consecutive_failures = 0; + sta->tx_num_mpdu_ok++; + } + sta->tx_retry_count += status->retry_count; + sta->tx_num_mpdu_fail += status->retry_count; + + /* Update PID controller state. */ + period = (HZ * pinfo->sampling_period + 500) / 1000; + if (!period) + period = 1; + if (time_after(jiffies, spinfo->last_sample + period)) + rate_control_pid_sample(pinfo, local, sta); + +ignore: + sta_info_put(sta); +} + +static void rate_control_pid_get_rate(void *priv, struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + int rateidx; + u16 fc; + + sta = sta_info_get(local, hdr->addr1); + + /* Send management frames and broadcast/multicast data using lowest + * rate. */ + fc = le16_to_cpu(hdr->frame_control); + if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + is_multicast_ether_addr(hdr->addr1) || !sta) { + sel->rate = rate_lowest(local, sband, sta); + if (sta) + sta_info_put(sta); + return; + } + + /* If a forced rate is in effect, select it. */ + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) + sta->txrate_idx = sdata->bss->force_unicast_rateidx; + + rateidx = sta->txrate_idx; + + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; + + sta->last_txrate_idx = rateidx; + + sta_info_put(sta); + + sel->rate = &sband->bitrates[rateidx]; + +#ifdef CONFIG_MAC80211_DEBUGFS + rate_control_pid_event_tx_rate( + &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events, + rateidx, sband->bitrates[rateidx].bitrate); +#endif +} + +static void rate_control_pid_rate_init(void *priv, void *priv_sta, + struct ieee80211_local *local, + struct sta_info *sta) +{ + /* TODO: This routine should consider using RSSI from previous packets + * as we need to have IEEE 802.1X auth succeed immediately after assoc.. + * Until that method is implemented, we will use the lowest supported + * rate as a workaround. */ + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sta->txrate_idx = rate_lowest_index(local, sband, sta); +} + +static void *rate_control_pid_alloc(struct ieee80211_local *local) +{ + struct rc_pid_info *pinfo; + struct rc_pid_rateinfo *rinfo; + struct ieee80211_supported_band *sband; + int i, j, tmp; + bool s; +#ifdef CONFIG_MAC80211_DEBUGFS + struct rc_pid_debugfs_entries *de; +#endif + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); + if (!pinfo) + return NULL; + + /* We can safely assume that sband won't change unless we get + * reinitialized. */ + rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC); + if (!rinfo) { + kfree(pinfo); + return NULL; + } + + /* Sort the rates. This is optimized for the most common case (i.e. + * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed + * mapping too. */ + for (i = 0; i < sband->n_bitrates; i++) { + rinfo[i].index = i; + rinfo[i].rev_index = i; + if (pinfo->fast_start) + rinfo[i].diff = 0; + else + rinfo[i].diff = i * pinfo->norm_offset; + } + for (i = 1; i < sband->n_bitrates; i++) { + s = 0; + for (j = 0; j < sband->n_bitrates - i; j++) + if (unlikely(sband->bitrates[rinfo[j].index].bitrate > + sband->bitrates[rinfo[j + 1].index].bitrate)) { + tmp = rinfo[j].index; + rinfo[j].index = rinfo[j + 1].index; + rinfo[j + 1].index = tmp; + rinfo[rinfo[j].index].rev_index = j; + rinfo[rinfo[j + 1].index].rev_index = j + 1; + s = 1; + } + if (!s) + break; + } + + pinfo->target = RC_PID_TARGET_PF; + pinfo->sampling_period = RC_PID_INTERVAL; + pinfo->coeff_p = RC_PID_COEFF_P; + pinfo->coeff_i = RC_PID_COEFF_I; + pinfo->coeff_d = RC_PID_COEFF_D; + pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT; + pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR; + pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION; + pinfo->norm_offset = RC_PID_NORM_OFFSET; + pinfo->fast_start = RC_PID_FAST_START; + pinfo->rinfo = rinfo; + pinfo->oldrate = 0; + +#ifdef CONFIG_MAC80211_DEBUGFS + de = &pinfo->dentries; + de->dir = debugfs_create_dir("rc80211_pid", + local->hw.wiphy->debugfsdir); + de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR, + de->dir, &pinfo->target); + de->sampling_period = debugfs_create_u32("sampling_period", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->sampling_period); + de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, + de->dir, &pinfo->coeff_p); + de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, + de->dir, &pinfo->coeff_i); + de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, + de->dir, &pinfo->coeff_d); + de->smoothing_shift = debugfs_create_u32("smoothing_shift", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->smoothing_shift); + de->sharpen_factor = debugfs_create_u32("sharpen_factor", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->sharpen_factor); + de->sharpen_duration = debugfs_create_u32("sharpen_duration", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->sharpen_duration); + de->norm_offset = debugfs_create_u32("norm_offset", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->norm_offset); + de->fast_start = debugfs_create_bool("fast_start", + S_IRUSR | S_IWUSR, de->dir, + &pinfo->fast_start); +#endif + + return pinfo; +} + +static void rate_control_pid_free(void *priv) +{ + struct rc_pid_info *pinfo = priv; +#ifdef CONFIG_MAC80211_DEBUGFS + struct rc_pid_debugfs_entries *de = &pinfo->dentries; + + debugfs_remove(de->fast_start); + debugfs_remove(de->norm_offset); + debugfs_remove(de->sharpen_duration); + debugfs_remove(de->sharpen_factor); + debugfs_remove(de->smoothing_shift); + debugfs_remove(de->coeff_d); + debugfs_remove(de->coeff_i); + debugfs_remove(de->coeff_p); + debugfs_remove(de->sampling_period); + debugfs_remove(de->target); + debugfs_remove(de->dir); +#endif + + kfree(pinfo->rinfo); + kfree(pinfo); +} + +static void rate_control_pid_clear(void *priv) +{ +} + +static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp) +{ + struct rc_pid_sta_info *spinfo; + + spinfo = kzalloc(sizeof(*spinfo), gfp); + if (spinfo == NULL) + return NULL; + + spinfo->last_sample = jiffies; + +#ifdef CONFIG_MAC80211_DEBUGFS + spin_lock_init(&spinfo->events.lock); + init_waitqueue_head(&spinfo->events.waitqueue); +#endif + + return spinfo; +} + +static void rate_control_pid_free_sta(void *priv, void *priv_sta) +{ + struct rc_pid_sta_info *spinfo = priv_sta; + kfree(spinfo); +} + +static struct rate_control_ops mac80211_rcpid = { + .name = "pid", + .tx_status = rate_control_pid_tx_status, + .get_rate = rate_control_pid_get_rate, + .rate_init = rate_control_pid_rate_init, + .clear = rate_control_pid_clear, + .alloc = rate_control_pid_alloc, + .free = rate_control_pid_free, + .alloc_sta = rate_control_pid_alloc_sta, + .free_sta = rate_control_pid_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = rate_control_pid_add_sta_debugfs, + .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs, +#endif +}; + +MODULE_DESCRIPTION("PID controller based rate control algorithm"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Mattias Nissler"); +MODULE_LICENSE("GPL"); + +int __init rc80211_pid_init(void) +{ + return ieee80211_rate_control_register(&mac80211_rcpid); +} + +void rc80211_pid_exit(void) +{ + ieee80211_rate_control_unregister(&mac80211_rcpid); +} + +#ifdef CONFIG_MAC80211_RC_PID_MODULE +module_init(rc80211_pid_init); +module_exit(rc80211_pid_exit); +#endif diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c new file mode 100644 index 0000000000..88b8dc9999 --- /dev/null +++ b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c @@ -0,0 +1,223 @@ +/* + * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/spinlock.h> +#include <linux/poll.h> +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/skbuff.h> + +#include <net/mac80211.h> +#include "ieee80211_rate.h" + +#include "rc80211_pid.h" + +static void rate_control_pid_event(struct rc_pid_event_buffer *buf, + enum rc_pid_event_type type, + union rc_pid_event_data *data) +{ + struct rc_pid_event *ev; + unsigned long status; + + spin_lock_irqsave(&buf->lock, status); + ev = &(buf->ring[buf->next_entry]); + buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; + + ev->timestamp = jiffies; + ev->id = buf->ev_count++; + ev->type = type; + ev->data = *data; + + spin_unlock_irqrestore(&buf->lock, status); + + wake_up_all(&buf->waitqueue); +} + +void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, + struct ieee80211_tx_status *stat) +{ + union rc_pid_event_data evd; + + memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status)); + rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); +} + +void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, + int index, int rate) +{ + union rc_pid_event_data evd; + + evd.index = index; + evd.rate = rate; + rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); +} + +void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, + int index, int rate) +{ + union rc_pid_event_data evd; + + evd.index = index; + evd.rate = rate; + rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); +} + +void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, + s32 pf_sample, s32 prop_err, + s32 int_err, s32 der_err) +{ + union rc_pid_event_data evd; + + evd.pf_sample = pf_sample; + evd.prop_err = prop_err; + evd.int_err = int_err; + evd.der_err = der_err; + rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); +} + +static int rate_control_pid_events_open(struct inode *inode, struct file *file) +{ + struct rc_pid_sta_info *sinfo = inode->i_private; + struct rc_pid_event_buffer *events = &sinfo->events; + struct rc_pid_events_file_info *file_info; + unsigned int status; + + /* Allocate a state struct */ + file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); + if (file_info == NULL) + return -ENOMEM; + + spin_lock_irqsave(&events->lock, status); + + file_info->next_entry = events->next_entry; + file_info->events = events; + + spin_unlock_irqrestore(&events->lock, status); + + file->private_data = file_info; + + return 0; +} + +static int rate_control_pid_events_release(struct inode *inode, + struct file *file) +{ + struct rc_pid_events_file_info *file_info = file->private_data; + + kfree(file_info); + + return 0; +} + +static unsigned int rate_control_pid_events_poll(struct file *file, + poll_table *wait) +{ + struct rc_pid_events_file_info *file_info = file->private_data; + + poll_wait(file, &file_info->events->waitqueue, wait); + + return POLLIN | POLLRDNORM; +} + +#define RC_PID_PRINT_BUF_SIZE 64 + +static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, + size_t length, loff_t *offset) +{ + struct rc_pid_events_file_info *file_info = file->private_data; + struct rc_pid_event_buffer *events = file_info->events; + struct rc_pid_event *ev; + char pb[RC_PID_PRINT_BUF_SIZE]; + int ret; + int p; + unsigned int status; + + /* Check if there is something to read. */ + if (events->next_entry == file_info->next_entry) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + /* Wait */ + ret = wait_event_interruptible(events->waitqueue, + events->next_entry != file_info->next_entry); + + if (ret) + return ret; + } + + /* Write out one event per call. I don't care whether it's a little + * inefficient, this is debugging code anyway. */ + spin_lock_irqsave(&events->lock, status); + + /* Get an event */ + ev = &(events->ring[file_info->next_entry]); + file_info->next_entry = (file_info->next_entry + 1) % + RC_PID_EVENT_RING_SIZE; + + /* Print information about the event. Note that userpace needs to + * provide large enough buffers. */ + length = length < RC_PID_PRINT_BUF_SIZE ? + length : RC_PID_PRINT_BUF_SIZE; + p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); + switch (ev->type) { + case RC_PID_EVENT_TYPE_TX_STATUS: + p += snprintf(pb + p, length - p, "tx_status %u %u", + ev->data.tx_status.excessive_retries, + ev->data.tx_status.retry_count); + break; + case RC_PID_EVENT_TYPE_RATE_CHANGE: + p += snprintf(pb + p, length - p, "rate_change %d %d", + ev->data.index, ev->data.rate); + break; + case RC_PID_EVENT_TYPE_TX_RATE: + p += snprintf(pb + p, length - p, "tx_rate %d %d", + ev->data.index, ev->data.rate); + break; + case RC_PID_EVENT_TYPE_PF_SAMPLE: + p += snprintf(pb + p, length - p, + "pf_sample %d %d %d %d", + ev->data.pf_sample, ev->data.prop_err, + ev->data.int_err, ev->data.der_err); + break; + } + p += snprintf(pb + p, length - p, "\n"); + + spin_unlock_irqrestore(&events->lock, status); + + if (copy_to_user(buf, pb, p)) + return -EFAULT; + + return p; +} + +#undef RC_PID_PRINT_BUF_SIZE + +static struct file_operations rc_pid_fop_events = { + .owner = THIS_MODULE, + .read = rate_control_pid_events_read, + .poll = rate_control_pid_events_poll, + .open = rate_control_pid_events_open, + .release = rate_control_pid_events_release, +}; + +void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct rc_pid_sta_info *spinfo = priv_sta; + + spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, + dir, spinfo, + &rc_pid_fop_events); +} + +void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) +{ + struct rc_pid_sta_info *spinfo = priv_sta; + + debugfs_remove(spinfo->events_entry); +} diff --git a/package/mac80211/src/net/mac80211/rc80211_simple.c b/package/mac80211/src/net/mac80211/rc80211_simple.c index ef91ce428a..c4678905a1 100644 --- a/package/mac80211/src/net/mac80211/rc80211_simple.c +++ b/package/mac80211/src/net/mac80211/rc80211_simple.c @@ -7,13 +7,13 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/compiler.h> +#include <linux/module.h> #include <net/mac80211.h> #include "ieee80211_i.h" @@ -24,19 +24,19 @@ /* This is a minimal implementation of TX rate controlling that can be used * as the default when no improved mechanisms are available. */ +#define RATE_CONTROL_NUM_DOWN 20 +#define RATE_CONTROL_NUM_UP 15 #define RATE_CONTROL_EMERG_DEC 2 #define RATE_CONTROL_INTERVAL (HZ / 20) #define RATE_CONTROL_MIN_TX 10 -MODULE_ALIAS("rc80211_default"); - static void rate_control_rate_inc(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; int maxrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); @@ -45,18 +45,17 @@ static void rate_control_rate_inc(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - if (i > mode->num_rates) - i = mode->num_rates - 2; + if (i > sband->n_bitrates) + i = sband->n_bitrates - 2; - while (i + 1 < mode->num_rates) { + while (i + 1 < sband->n_bitrates) { i++; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED && + if (rate_supported(sta, sband->band, i) && (maxrate < 0 || i <= maxrate)) { - sta->txrate = i; + sta->txrate_idx = i; break; } } @@ -67,8 +66,8 @@ static void rate_control_rate_dec(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { @@ -76,40 +75,19 @@ static void rate_control_rate_dec(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; - if (i > mode->num_rates) - i = mode->num_rates; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + if (i > sband->n_bitrates) + i = sband->n_bitrates; while (i > 0) { i--; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { - sta->txrate = i; + if (rate_supported(sta, sband->band, i)) { + sta->txrate_idx = i; break; } } } - -static struct ieee80211_rate * -rate_control_lowest_rate(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - if (rate->flags & IEEE80211_RATE_SUPPORTED) - return rate; - } - - printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates " - "found\n"); - return &mode->rates[0]; -} - - struct global_rate_control { int dummy; }; @@ -188,7 +166,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, } else if (per_failed < RATE_CONTROL_NUM_UP) { rate_control_rate_inc(local, sta); } - srctrl->tx_avg_rate_sum += status->control.rate->rate; + srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate; srctrl->tx_avg_rate_num++; srctrl->tx_num_failures = 0; srctrl->tx_num_xmit = 0; @@ -201,9 +179,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: " + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: STA %s Average rate: " "%d (%d/%d)\n", - dev->name, MAC_ARG(sta->addr), + dev->name, print_mac(mac, sta->addr), srctrl->tx_avg_rate_sum / srctrl->tx_avg_rate_num, srctrl->tx_avg_rate_sum, @@ -218,56 +197,47 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, } -static struct ieee80211_rate * +static void rate_control_simple_get_rate(void *priv, struct net_device *dev, + struct ieee80211_supported_band *sband, struct sk_buff *skb, - struct rate_control_extra *extra) + struct rate_selection *sel) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_hw_mode *mode = extra->mode; + struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - int rateidx, nonerp_idx; + int rateidx; u16 fc; - memset(extra, 0, sizeof(*extra)); + sta = sta_info_get(local, hdr->addr1); + /* Send management frames and broadcast/multicast data using lowest + * rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - (hdr->addr1[0] & 0x01)) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ - return rate_control_lowest_rate(local, mode); + is_multicast_ether_addr(hdr->addr1) || !sta) { + sel->rate = rate_lowest(local, sband, sta); + if (sta) + sta_info_put(sta); + return; } - sta = sta_info_get(local, hdr->addr1); - - if (!sta) - return rate_control_lowest_rate(local, mode); - + /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate = sdata->bss->force_unicast_rateidx; + sta->txrate_idx = sdata->bss->force_unicast_rateidx; - rateidx = sta->txrate; + rateidx = sta->txrate_idx; - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; - sta->last_txrate = rateidx; - nonerp_idx = rateidx; - while (nonerp_idx > 0 && - ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) || - !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) || - !(sta->supp_rates & BIT(nonerp_idx)))) - nonerp_idx--; - extra->nonerp = &mode->rates[nonerp_idx]; + sta->last_txrate_idx = rateidx; sta_info_put(sta); - return &mode->rates[rateidx]; + sel->rate = &sband->bitrates[rateidx]; } @@ -275,21 +245,15 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta) { - struct ieee80211_hw_mode *mode; - int i; - sta->txrate = 0; - mode = local->oper_hw_mode; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* TODO: This routine should consider using RSSI from previous packets * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported rate * as a workaround, */ - for (i = 0; i < mode->num_rates; i++) { - if ((sta->supp_rates & BIT(i)) && - (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) { - sta->txrate = i; - break; - } - } + sta->txrate_idx = rate_lowest_index(local, sband, sta); } @@ -393,8 +357,7 @@ static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta) } #endif -static struct rate_control_ops rate_control_simple = { - .module = THIS_MODULE, +static struct rate_control_ops mac80211_rcsimple = { .name = "simple", .tx_status = rate_control_simple_tx_status, .get_rate = rate_control_simple_get_rate, @@ -410,21 +373,20 @@ static struct rate_control_ops rate_control_simple = { #endif }; +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple rate control algorithm"); -static int __init rate_control_simple_init(void) +int __init rc80211_simple_init(void) { - return ieee80211_rate_control_register(&rate_control_simple); + return ieee80211_rate_control_register(&mac80211_rcsimple); } - -static void __exit rate_control_simple_exit(void) +void rc80211_simple_exit(void) { - ieee80211_rate_control_unregister(&rate_control_simple); + ieee80211_rate_control_unregister(&mac80211_rcsimple); } - -subsys_initcall(rate_control_simple_init); -module_exit(rate_control_simple_exit); - -MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211"); -MODULE_LICENSE("GPL"); +#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE +module_init(rc80211_simple_init); +module_exit(rc80211_simple_exit); +#endif diff --git a/package/mac80211/src/net/mac80211/regdomain.c b/package/mac80211/src/net/mac80211/regdomain.c deleted file mode 100644 index f42678fa62..0000000000 --- a/package/mac80211/src/net/mac80211/regdomain.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * This regulatory domain control implementation is known to be incomplete - * and confusing. mac80211 regulatory domain control will be significantly - * reworked in the not-too-distant future. - * - * For now, drivers wishing to control which channels are and aren't available - * are advised as follows: - * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag - * - continue to include *ALL* possible channels in the modes registered - * through ieee80211_register_hwmode() - * - for each allowable ieee80211_channel structure registered in the above - * call, set the flag member to some meaningful value such as - * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | - * IEEE80211_CHAN_W_IBSS. - * - leave flag as 0 for non-allowable channels - * - * The usual implementation is for a driver to read a device EEPROM to - * determine which regulatory domain it should be operating under, then - * looking up the allowable channels in a driver-local table, then performing - * the above. - */ - -#include <linux/module.h> -#include <linux/netdevice.h> -#include <net/mac80211.h> -#include "ieee80211_i.h" - -static int ieee80211_regdom = 0x10; /* FCC */ -module_param(ieee80211_regdom, int, 0444); -MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); - -/* - * If firmware is upgraded by the vendor, additional channels can be used based - * on the new Japanese regulatory rules. This is indicated by setting - * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel - * module. - */ -static int ieee80211_japan_5ghz /* = 0 */; -module_param(ieee80211_japan_5ghz, int, 0444); -MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); - - -struct ieee80211_channel_range { - short start_freq; - short end_freq; - unsigned char power_level; - unsigned char antenna_max; -}; - -static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { - { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, - { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, - { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, - { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, - { 0 } -}; - -static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { - { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, - { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, - { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, - { 0 } -}; - - -static const struct ieee80211_channel_range *channel_range = - ieee80211_fcc_channels; - - -static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) -{ - int i; - - chan->flag = 0; - - for (i = 0; channel_range[i].start_freq; i++) { - const struct ieee80211_channel_range *r = &channel_range[i]; - if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { - if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && - chan->freq >= 5260 && chan->freq <= 5320) { - /* - * Skip new channels in Japan since the - * firmware was not marked having been upgraded - * by the vendor. - */ - continue; - } - - if (ieee80211_regdom == 0x10 && - (chan->freq == 5190 || chan->freq == 5210 || - chan->freq == 5230)) { - /* Skip MKK channels when in FCC domain. */ - continue; - } - - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; - chan->power_level = r->power_level; - chan->antenna_max = r->antenna_max; - - if (ieee80211_regdom == 64 && - (chan->freq == 5170 || chan->freq == 5190 || - chan->freq == 5210 || chan->freq == 5230)) { - /* - * New regulatory rules in Japan have backwards - * compatibility with old channels in 5.15-5.25 - * GHz band, but the station is not allowed to - * use active scan on these old channels. - */ - chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; - } - - if (ieee80211_regdom == 64 && - (chan->freq == 5260 || chan->freq == 5280 || - chan->freq == 5300 || chan->freq == 5320)) { - /* - * IBSS is not allowed on 5.25-5.35 GHz band - * due to radar detection requirements. - */ - chan->flag &= ~IEEE80211_CHAN_W_IBSS; - } - - break; - } - } -} - - -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode) -{ - int c; - for (c = 0; c < mode->num_channels; c++) - ieee80211_unmask_channel(mode->mode, &mode->channels[c]); -} - - -void ieee80211_regdomain_init(void) -{ - if (ieee80211_regdom == 0x40) - channel_range = ieee80211_mkk_channels; -} - diff --git a/package/mac80211/src/net/mac80211/rx.c b/package/mac80211/src/net/mac80211/rx.c index 064924cb28..943ba90829 100644 --- a/package/mac80211/src/net/mac80211/rx.c +++ b/package/mac80211/src/net/mac80211/rx.c @@ -24,6 +24,10 @@ #include "tkip.h" #include "wme.h" +u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb, u16 mpdu_seq_num, + int bar_req); /* * monitor mode reception * @@ -61,8 +65,12 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, return 1; if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) return 1; - if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == - cpu_to_le16(IEEE80211_FTYPE_CTL)) + if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL)) && + ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != + cpu_to_le16(IEEE80211_STYPE_PSPOLL)) && + ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != + cpu_to_le16(IEEE80211_STYPE_BACK_REQ))) return 1; return 0; } @@ -74,13 +82,14 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, */ static struct sk_buff * ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, - struct ieee80211_rx_status *status) + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_rate *rate; int needed_headroom = 0; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header *rthdr; + __le64 *rttsft = NULL; + struct ieee80211_rtap_fixed_data { u8 flags; u8 rate; __le16 chan_freq; @@ -88,7 +97,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, u8 antsignal; u8 padding_for_rxflags; __le16 rx_flags; - } __attribute__ ((packed)) *rthdr; + } __attribute__ ((packed)) *rtfixed; struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; @@ -105,7 +114,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (status->flag & RX_FLAG_RADIOTAP) rtap_len = ieee80211_get_radiotap_len(origskb->data); else - needed_headroom = sizeof(*rthdr); + /* room for radiotap header, always present fields and TSFT */ + needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; @@ -133,7 +143,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, * them allocate enough headroom to start with. */ if (skb_headroom(skb) < needed_headroom && - pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { + pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return NULL; } @@ -152,45 +162,56 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, /* if necessary, prepend radiotap information */ if (!(status->flag & RX_FLAG_RADIOTAP)) { + rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); + rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); + if (status->flag & RX_FLAG_TSFT) { + rttsft = (void *) skb_push(skb, sizeof(*rttsft)); + rtap_len += 8; + } rthdr = (void *) skb_push(skb, sizeof(*rthdr)); memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = + memset(rtfixed, 0, sizeof(*rtfixed)); + rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? - IEEE80211_RADIOTAP_F_FCS : 0; + rtfixed->flags = 0; + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS; + + if (rttsft) { + *rttsft = cpu_to_le64(status->mactime); + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + } /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ - rthdr->rx_flags = 0; + rtfixed->rx_flags = 0; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) - rthdr->rx_flags |= + rtfixed->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); - rate = ieee80211_get_rate(local, status->phymode, - status->rate); - if (rate) - rthdr->rate = rate->rate / 5; + rtfixed->rate = rate->bitrate / 5; - rthdr->chan_freq = cpu_to_le16(status->freq); + rtfixed->chan_freq = cpu_to_le16(status->freq); - if (status->phymode == MODE_IEEE80211A) - rthdr->chan_flags = + if (status->band == IEEE80211_BAND_5GHZ) + rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ); else - rthdr->chan_flags = + rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rthdr->antsignal = status->ssi; + rtfixed->antsignal = status->ssi; + rthdr->it_len = cpu_to_le16(rtap_len); } - skb_set_mac_header(skb, 0); + skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); @@ -199,7 +220,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (!netif_running(sdata->dev)) continue; - if (sdata->type != IEEE80211_IF_TYPE_MNTR) + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR) + continue; + + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) continue; if (prev_dev) { @@ -225,15 +249,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, } -/* pre-rx handlers - * - * these don't have dev/sdata fields in the rx data - * The sta value should also not be used because it may - * be NULL even though a STA (in IBSS mode) will be added. - */ - -static ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) +static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) { u8 *data = rx->skb->data; int tid; @@ -243,6 +259,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; /* frame has qos control */ tid = qc[0] & QOS_CONTROL_TID_MASK; + if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + rx->flags |= IEEE80211_TXRXD_RX_AMSDU; + else + rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU; } else { if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { /* Separate TID for management frames */ @@ -262,40 +282,59 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ rx->skb->priority = (tid > 7) ? 0 : tid; +} + +static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) +{ +#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT + int hdrlen; - return TXRX_CONTINUE; + if (!WLAN_FC_DATA_PRESENT(rx->fc)) + return; + + /* + * Drivers are required to align the payload data in a way that + * guarantees that the contained IP header is aligned to a four- + * byte boundary. In the case of regular frames, this simply means + * aligning the payload to a four-byte boundary (because either + * the IP header is directly contained, or IV/RFC1042 headers that + * have a length divisible by four are in front of it. + * + * With A-MSDU frames, however, the payload data address must + * yield two modulo four because there are 14-byte 802.3 headers + * within the A-MSDU frames that push the IP header further back + * to a multiple of four again. Thankfully, the specs were sane + * enough this time around to require padding each A-MSDU subframe + * to a length that is a multiple of four. + * + * Padding like atheros hardware adds which is inbetween the 802.11 + * header and the payload is not supported, the driver is required + * to move the 802.11 header further back in that case. + */ + hdrlen = ieee80211_get_hdrlen(rx->fc); + if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) + hdrlen += ETH_HLEN; + WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); +#endif } -static ieee80211_txrx_result -ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) + +static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { - struct ieee80211_local *local = rx->local; - struct sk_buff *skb = rx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode = local->hw.conf.mode; - int i; /* Estimate total channel use caused by this frame */ - if (unlikely(mode->num_rates < 0)) - return TXRX_CONTINUE; - - rate = &mode->rates[0]; - for (i = 0; i < mode->num_rates; i++) { - if (mode->rates[i].val == rx->u.rx.status->rate) { - rate = &mode->rates[i]; - break; - } - } - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - rate->flags & IEEE80211_RATE_ERP)) + if (status->band == IEEE80211_BAND_5GHZ || + (status->band == IEEE80211_BAND_5GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -304,55 +343,53 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; - load += skb->len * rate->rate_inv; + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; /* Divide channel_use by 8 to avoid wrapping around the counter */ load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - rx->u.rx.load = load; - return TXRX_CONTINUE; + return load; } -ieee80211_rx_handler ieee80211_rx_pre_handlers[] = -{ - ieee80211_rx_h_parse_qos, - ieee80211_rx_h_load_stats, - NULL -}; - /* rx handlers */ -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) { if (rx->sta) rx->sta->channel_use_raw += rx->u.rx.load; rx->sdata->channel_use_raw += rx->u.rx.load; - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) { struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(local->sta_scanning != 0)) { - ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); - return TXRX_QUEUED; + if (unlikely(local->sta_hw_scanning)) + return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + + if (unlikely(local->sta_sw_scanning)) { + /* drop all the other packets during a software scan anyway */ + if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) + != RX_QUEUED) + dev_kfree_skb(skb); + return RX_QUEUED; } if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -367,28 +404,16 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } - return TXRX_DROP; + return RX_DROP_MONITOR; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; + return RX_DROP_MONITOR; } - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - rx->skb->pkt_type = PACKET_OTHERHOST; - else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) - rx->skb->pkt_type = PACKET_HOST; - else if (is_multicast_ether_addr(hdr->addr1)) { - if (is_broadcast_ether_addr(hdr->addr1)) - rx->skb->pkt_type = PACKET_BROADCAST; - else - rx->skb->pkt_type = PACKET_MULTICAST; - } else - rx->skb->pkt_type = PACKET_OTHERHOST; - /* Drop disallowed frame classes based on STA auth/assoc state; * IEEE 802.11, Chap 5.5. * @@ -400,7 +425,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && - rx->sdata->type != IEEE80211_IF_TYPE_IBSS && + rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && !(rx->fc & IEEE80211_FCTL_TODS) && @@ -408,23 +433,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ - return TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; - ieee80211_txrx_result result = TXRX_DROP; + ieee80211_rx_result result = RX_DROP_UNUSABLE; struct ieee80211_key *stakey = NULL; /* @@ -454,14 +479,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (rx->sta) stakey = rcu_dereference(rx->sta->key); @@ -480,12 +505,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); if (rx->skb->len < 8 + hdrlen) - return TXRX_DROP; /* TODO: count this? */ + return RX_DROP_UNUSABLE; /* TODO: count this? */ /* * no need to call ieee80211_wep_get_keyidx, @@ -509,10 +534,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) rx->key->tx_rx_count++; /* TODO: add threshold stuff again */ } else { +#ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: RX protected frame," " but have no key\n", rx->dev->name); - return TXRX_DROP; +#endif /* CONFIG_MAC80211_DEBUG */ + return RX_DROP_MONITOR; } /* Check for weak IVs if possible */ @@ -544,6 +571,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; + DECLARE_MAC_BUF(mac); + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -551,8 +580,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) sta->flags |= WLAN_STA_PS; sta->pspoll = 0; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -563,6 +592,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) int sent = 0; struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_packet_data *pkt_data; + DECLARE_MAC_BUF(mac); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -576,8 +606,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) bss_tim_clear(local, sdata->bss, sta->aid); } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { @@ -591,9 +621,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " + printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " "since STA not sleeping anymore\n", dev->name, - MAC_ARG(sta->addr), sta->aid); + print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ pkt_data->flags |= IEEE80211_TXPD_REQUEUE; dev_queue_xmit(skb); @@ -602,7 +632,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) return sent; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) { struct sta_info *sta = rx->sta; @@ -610,18 +640,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; if (!sta) - return TXRX_CONTINUE; + return RX_CONTINUE; /* Update last_rx only for IBSS packets which are for the current * BSSID to avoid keeping the current IBSS network alive in cases where * other STAs are using different BSSID. */ - if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { - u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); + if (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, + IEEE80211_IF_TYPE_IBSS); if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) sta->last_rx = jiffies; } else if (!is_multicast_ether_addr(hdr->addr1) || - rx->sdata->type == IEEE80211_IF_TYPE_STA) { + rx->sdata->vif.type == IEEE80211_IF_TYPE_STA) { /* Update last_rx only for unicast frames in order to prevent * the Probe Request frames (the only broadcast frames from a * STA in infrastructure mode) from keeping a connection alive. @@ -630,7 +661,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) } if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; sta->rx_fragments++; sta->rx_bytes += rx->skb->len; @@ -657,10 +688,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) * as a dropped packed. */ sta->rx_packets++; dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } - return TXRX_CONTINUE; + return RX_CONTINUE; } /* ieee80211_rx_h_sta_process */ static inline struct ieee80211_fragment_entry * @@ -680,13 +711,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", + "addr1=%s addr2=%s\n", sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2)); + entry->last_frag, print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2)); #endif /* CONFIG_MAC80211_DEBUG */ __skb_queue_purge(&entry->skb_list); } @@ -744,7 +777,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -752,6 +785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr *) rx->skb->data; sc = le16_to_cpu(hdr->seq_ctrl); @@ -780,7 +814,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN); } - return TXRX_QUEUED; + return RX_QUEUED; } /* This is a fragment for a frame that should already be pending in @@ -790,7 +824,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->u.rx.queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return TXRX_DROP; + return RX_DROP_MONITOR; } /* Verify that MPDUs within one MSDU have sequential PN values. @@ -799,7 +833,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) int i; u8 pn[CCMP_PN_LEN], *rpn; if (!rx->key || rx->key->conf.alg != ALG_CCMP) - return TXRX_DROP; + return RX_DROP_UNUSABLE; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; @@ -810,14 +844,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { if (net_ratelimit()) printk(KERN_DEBUG "%s: defrag: CCMP PN not " - "sequential A2=" MAC_FMT + "sequential A2=%s" " PN=%02x%02x%02x%02x%02x%02x " "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), + rx->dev->name, print_mac(mac, hdr->addr2), rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -828,7 +862,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) entry->extra_len += rx->skb->len; if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { rx->skb = NULL; - return TXRX_QUEUED; + return RX_QUEUED; } rx->skb = __skb_dequeue(&entry->skb_list); @@ -838,7 +872,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); __skb_queue_purge(&entry->skb_list); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } } while ((skb = __skb_dequeue(&entry->skb_list))) { @@ -856,20 +890,26 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->local->dot11MulticastReceivedFrameCount++; else ieee80211_led_rx(rx->local); - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); struct sk_buff *skb; int no_pending_pkts; + DECLARE_MAC_BUF(mac); if (likely(!rx->sta || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) - return TXRX_CONTINUE; + return RX_CONTINUE; + + if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && + (sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) + return RX_DROP_UNUSABLE; skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { @@ -889,9 +929,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) rx->sta->pspoll = 1; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " - "after %d)\n", - MAC_ARG(rx->sta->addr), rx->sta->aid, + printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", + print_mac(mac, rx->sta->addr), rx->sta->aid, skb_queue_len(&rx->sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -914,21 +953,21 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " + printk(KERN_DEBUG "%s: STA %s sent PS Poll even " "though there is no buffered frames for it\n", - rx->dev->name, MAC_ARG(rx->sta->addr)); + rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } - /* Free PS Poll skb here instead of returning TXRX_DROP that would + /* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */ dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) { u16 fc = rx->fc; @@ -936,7 +975,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; if (!WLAN_FC_IS_QOS_DATA(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* remove the qos control field, update frame type and meta-data */ memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); @@ -945,78 +984,67 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; hdr->frame_control = cpu_to_le16(fc); - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) +static int +ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) { - if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA && - (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; - - if (unlikely(rx->sdata->ieee802_1x && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && - !ieee80211_is_eapol(rx->skb))) { + if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) rx->skb->data; - printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT - " (unauthorized port)\n", rx->dev->name, - MAC_ARG(hdr->addr2)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped frame " + "(unauthorized port)\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return -EACCES; } - return TXRX_CONTINUE; + return 0; } -static ieee80211_txrx_result -ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) +static int +ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) { /* * Pass through unencrypted frames if the hardware has * decrypted them already. */ if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) - return TXRX_CONTINUE; + return 0; /* Drop unencrypted frames if key is set. */ if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - rx->sdata->drop_unencrypted && - (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) { + (rx->key || rx->sdata->drop_unencrypted))) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " "encryption\n", rx->dev->name); - return TXRX_DROP; + return -EACCES; } - return TXRX_CONTINUE; + return 0; } -static ieee80211_txrx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +static int +ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; - struct ieee80211_local *local = rx->local; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc, hdrlen, ethertype; u8 *payload; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct sk_buff *skb = rx->skb, *skb2; + struct sk_buff *skb = rx->skb; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); fc = rx->fc; - if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return -1; hdrlen = ieee80211_get_hdrlen(fc); @@ -1036,18 +1064,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr2, ETH_ALEN); - if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && - sdata->type != IEEE80211_IF_TYPE_VLAN)) { + if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP && + sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped ToDS frame " - "(BSSID=" MAC_FMT - " SA=" MAC_FMT - " DA=" MAC_FMT ")\n", + "(BSSID=%s SA=%s DA=%s)\n", dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - return TXRX_DROP; + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); + return -1; } break; case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): @@ -1055,18 +1081,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr4, ETH_ALEN); - if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { + if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped FromDS&ToDS " - "frame (RA=" MAC_FMT - " TA=" MAC_FMT " DA=" MAC_FMT - " SA=" MAC_FMT ")\n", + "frame (RA=%s TA=%s DA=%s SA=%s)\n", rx->dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); - return TXRX_DROP; + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3), + print_mac(mac4, hdr->addr4)); + return -1; } break; case IEEE80211_FCTL_FROMDS: @@ -1074,40 +1098,39 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr3, ETH_ALEN); - if (sdata->type != IEEE80211_IF_TYPE_STA || + if (sdata->vif.type != IEEE80211_IF_TYPE_STA || (is_multicast_ether_addr(dst) && !compare_ether_addr(src, dev->dev_addr))) - return TXRX_DROP; + return -1; break; case 0: /* DA SA BSSID */ memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr2, ETH_ALEN); - if (sdata->type != IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" - MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT - ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + printk(KERN_DEBUG "%s: dropped IBSS frame " + "(DA=%s SA=%s BSSID=%s)\n", + dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); } - return TXRX_DROP; + return -1; } break; } - payload = skb->data + hdrlen; - if (unlikely(skb->len - hdrlen < 8)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: RX too short data frame " "payload\n", dev->name); } - return TXRX_DROP; + return -1; } + payload = skb->data + hdrlen; ethertype = (payload[6] << 8) | payload[7]; if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && @@ -1121,6 +1144,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) } else { struct ethhdr *ehdr; __be16 len; + skb_pull(skb, hdrlen); len = htons(skb->len); ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); @@ -1128,36 +1152,72 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(ehdr->h_source, src, ETH_ALEN); ehdr->h_proto = len; } - skb->dev = dev; + return 0; +} - skb2 = NULL; +/* + * requires that rx->skb is a frame with ethernet header + */ +static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) +{ + static const u8 pae_group_addr[ETH_ALEN] + = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; + struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; + /* + * Allow EAPOL frames to us/the PAE group address regardless + * of whether the frame was encrypted or not. + */ + if (ehdr->h_proto == htons(ETH_P_PAE) && + (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 || + compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) + return true; + + if (ieee80211_802_1x_port_control(rx) || + ieee80211_drop_unencrypted(rx)) + return false; + + return true; +} + +/* + * requires that rx->skb is a frame with ethernet header + */ +static void +ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + struct sk_buff *skb, *xmit_skb; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; + struct sta_info *dsta; - if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN) && + skb = rx->skb; + xmit_skb = NULL; + + if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP || + sdata->vif.type == IEEE80211_IF_TYPE_VLAN) && (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { - if (is_multicast_ether_addr(skb->data)) { - /* send multicast frames both to higher layers in - * local net stack and back to the wireless media */ - skb2 = skb_copy(skb, GFP_ATOMIC); - if (!skb2 && net_ratelimit()) + if (is_multicast_ether_addr(ehdr->h_dest)) { + /* + * send multicast frames both to higher layers in + * local net stack and back to the wireless medium + */ + xmit_skb = skb_copy(skb, GFP_ATOMIC); + if (!xmit_skb && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone " "multicast frame\n", dev->name); } else { - struct sta_info *dsta; dsta = sta_info_get(local, skb->data); - if (dsta && !dsta->dev) { - if (net_ratelimit()) - printk(KERN_DEBUG "Station with null " - "dev structure!\n"); - } else if (dsta && dsta->dev == dev) { - /* Destination station is associated to this - * AP, so send the frame directly to it and - * do not pass the frame to local net stack. + if (dsta && dsta->dev == dev) { + /* + * The destination station is associated to + * this AP (in this VLAN), so send the frame + * directly to it and do not pass it to local + * net stack. */ - skb2 = skb; + xmit_skb = skb; skb = NULL; } if (dsta) @@ -1172,84 +1232,232 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) netif_rx(skb); } - if (skb2) { + if (xmit_skb) { /* send to wireless media */ - skb2->protocol = __constant_htons(ETH_P_802_3); - skb_set_network_header(skb2, 0); - skb_set_mac_header(skb2, 0); - dev_queue_xmit(skb2); + xmit_skb->protocol = __constant_htons(ETH_P_802_3); + skb_reset_network_header(xmit_skb); + skb_reset_mac_header(xmit_skb); + dev_queue_xmit(xmit_skb); } - - return TXRX_QUEUED; } -static ieee80211_txrx_result -ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) { - struct ieee80211_sub_if_data *sdata; + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + u16 fc, ethertype; + u8 *payload; + struct sk_buff *skb = rx->skb, *frame = NULL; + const struct ethhdr *eth; + int remaining, err; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + DECLARE_MAC_BUF(mac); - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return RX_CONTINUE; - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - if ((sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) && - !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) - ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); - else - return TXRX_DROP; + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return RX_DROP_MONITOR; - return TXRX_QUEUED; + if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) + return RX_CONTINUE; + + err = ieee80211_data_to_8023(rx); + if (unlikely(err)) + return RX_DROP_UNUSABLE; + + skb->dev = dev; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) + return RX_DROP_UNUSABLE; + + while (skb != frame) { + u8 padding; + __be16 len = eth->h_proto; + unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); + + remaining = skb->len; + memcpy(dst, eth->h_dest, ETH_ALEN); + memcpy(src, eth->h_source, ETH_ALEN); + + padding = ((4 - subframe_len) & 0x3); + /* the last MSDU has no padding */ + if (subframe_len > remaining) { + printk(KERN_DEBUG "%s: wrong buffer size", dev->name); + return RX_DROP_UNUSABLE; + } + + skb_pull(skb, sizeof(struct ethhdr)); + /* if last subframe reuse skb */ + if (remaining <= subframe_len + padding) + frame = skb; + else { + frame = dev_alloc_skb(local->hw.extra_tx_headroom + + subframe_len); + + if (frame == NULL) + return RX_DROP_UNUSABLE; + + skb_reserve(frame, local->hw.extra_tx_headroom + + sizeof(struct ethhdr)); + memcpy(skb_put(frame, ntohs(len)), skb->data, + ntohs(len)); + + eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + + padding); + if (!eth) { + printk(KERN_DEBUG "%s: wrong buffer size ", + dev->name); + dev_kfree_skb(frame); + return RX_DROP_UNUSABLE; + } + } + + skb_reset_network_header(frame); + frame->dev = dev; + frame->priority = skb->priority; + rx->skb = frame; + + payload = frame->data; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, + bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel + * encapsulation and replace EtherType */ + skb_pull(frame, 6); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } else { + memcpy(skb_push(frame, sizeof(__be16)), + &len, sizeof(__be16)); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } + + if (!ieee80211_frame_allowed(rx)) { + if (skb == frame) /* last frame */ + return RX_DROP_UNUSABLE; + dev_kfree_skb(frame); + continue; + } + + ieee80211_deliver_skb(rx); + } + + return RX_QUEUED; } -static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( - struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) +static ieee80211_rx_result +ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) { - ieee80211_rx_handler *handler; - ieee80211_txrx_result res = TXRX_DROP; + struct net_device *dev = rx->dev; + u16 fc; + int err; - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return RX_CONTINUE; - switch (res) { - case TXRX_CONTINUE: - continue; - case TXRX_DROP: - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - break; - case TXRX_QUEUED: - I802_DEBUG_INC(local->rx_handlers_queued); - break; + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return RX_DROP_MONITOR; + + err = ieee80211_data_to_8023(rx); + if (unlikely(err)) + return RX_DROP_UNUSABLE; + + if (!ieee80211_frame_allowed(rx)) + return RX_DROP_MONITOR; + + rx->skb->dev = dev; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += rx->skb->len; + + ieee80211_deliver_skb(rx); + + return RX_QUEUED; +} + +static ieee80211_rx_result +ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_local *local = rx->local; + struct ieee80211_hw *hw = &local->hw; + struct sk_buff *skb = rx->skb; + struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data; + struct tid_ampdu_rx *tid_agg_rx; + u16 start_seq_num; + u16 tid; + + if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL)) + return RX_CONTINUE; + + if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) { + if (!rx->sta) + return RX_CONTINUE; + tid = le16_to_cpu(bar->control) >> 12; + tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]); + if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) + return RX_CONTINUE; + + start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; + + /* reset session timer */ + if (tid_agg_rx->timeout) { + unsigned long expires = + jiffies + (tid_agg_rx->timeout / 1000) * HZ; + mod_timer(&tid_agg_rx->session_timer, expires); } - break; + + /* manage reordering buffer according to requested */ + /* sequence number */ + rcu_read_lock(); + ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, + start_seq_num, 1); + rcu_read_unlock(); + return RX_DROP_UNUSABLE; } - if (res == TXRX_DROP) - dev_kfree_skb(rx->skb); - return res; + return RX_CONTINUE; } -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) +static ieee80211_rx_result +ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { - if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - TXRX_CONTINUE) - dev_kfree_skb(rx->skb); + struct ieee80211_sub_if_data *sdata; + + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return RX_DROP_MONITOR; + + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); + if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) + ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); + else + return RX_DROP_MONITOR; + + return RX_QUEUED; } static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta, struct ieee80211_txrx_data *rx) { int keyidx, hdrlen; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); if (rx->skb->len >= hdrlen + 4) @@ -1259,19 +1467,19 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), - keyidx); + "failure from %s to %s keyidx=%d\n", + dev->name, print_mac(mac, hdr->addr2), + print_mac(mac2, hdr->addr1), keyidx); - if (!sta) { + if (!rx->sta) { /* * Some hardware seem to generate incorrect Michael MIC * reports; ignore them to avoid triggering countermeasures. */ if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); + "error for unknown address %s\n", + dev->name, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1279,11 +1487,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame with no PROTECTED flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); + "%s)\n", dev->name, print_mac(mac, hdr->addr2)); goto ignore; } - if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { + if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) { /* * APs with pairwise keys should never receive Michael MIC * errors for non-zero keyidx because these are reserved for @@ -1293,8 +1501,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored Michael MIC error for " "a frame with non-zero keyidx (%d)" - " (src " MAC_FMT ")\n", dev->name, keyidx, - MAC_ARG(hdr->addr2)); + " (src %s)\n", dev->name, keyidx, + print_mac(mac, hdr->addr2)); goto ignore; } @@ -1304,8 +1512,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); + "(fc=0x%04x) (src %s)\n", + dev->name, rx->fc, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1315,7 +1523,88 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } -ieee80211_rx_handler ieee80211_rx_handlers[] = +static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = rx->local; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + } __attribute__ ((packed)) *rthdr; + struct sk_buff *skb = rx->skb, *skb2; + struct net_device *prev_dev = NULL; + struct ieee80211_rx_status *status = rx->u.rx.status; + + if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) + goto out_free_skb; + + if (skb_headroom(skb) < sizeof(*rthdr) && + pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) + goto out_free_skb; + + rthdr = (void *)skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL)); + + rthdr->rate = rx->u.rx.rate->bitrate / 5; + rthdr->chan_freq = cpu_to_le16(status->freq); + + if (status->band == IEEE80211_BAND_5GHZ) + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || + !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + sdata->dev->stats.rx_packets++; + sdata->dev->stats.rx_bytes += skb->len; + } + + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } else + goto out_free_skb; + + rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; + return; + + out_free_skb: + dev_kfree_skb(skb); +} + +typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); +static ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, @@ -1330,13 +1619,54 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = * are not passed to user space by these functions */ ieee80211_rx_h_remove_qos_control, - ieee80211_rx_h_802_1x_pae, - ieee80211_rx_h_drop_unencrypted, + ieee80211_rx_h_amsdu, ieee80211_rx_h_data, + ieee80211_rx_h_ctrl, ieee80211_rx_h_mgmt, NULL }; +static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, + struct ieee80211_txrx_data *rx, + struct sk_buff *skb) +{ + ieee80211_rx_handler *handler; + ieee80211_rx_result res = RX_DROP_MONITOR; + + rx->skb = skb; + rx->sdata = sdata; + rx->dev = sdata->dev; + + for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) { + res = (*handler)(rx); + + switch (res) { + case RX_CONTINUE: + continue; + case RX_DROP_UNUSABLE: + case RX_DROP_MONITOR: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + break; + case RX_QUEUED: + I802_DEBUG_INC(sdata->local->rx_handlers_queued); + break; + } + break; + } + + switch (res) { + case RX_CONTINUE: + case RX_DROP_MONITOR: + ieee80211_rx_cooked_monitor(rx); + break; + case RX_DROP_UNUSABLE: + dev_kfree_skb(rx->skb); + break; + } +} + /* main receive path */ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, @@ -1345,7 +1675,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, { int multicast = is_multicast_ether_addr(hdr->addr1); - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_STA: if (!bssid) return 0; @@ -1416,99 +1746,70 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } /* - * This is the receive path handler. It is called by a low level driver when an - * 802.11 MPDU is received from the hardware. + * This is the actual Rx frames handler. as it blongs to Rx path it must + * be called with rcu_read_lock protection. */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_rx_status *status, + u32 load, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; struct ieee80211_hdr *hdr; struct ieee80211_txrx_data rx; u16 type; - int prepres; + int prepares; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid; - /* - * key references and virtual interfaces are protected using RCU - * and this requires that we are in a read-side RCU section during - * receive processing - */ - rcu_read_lock(); - - /* - * Frames with failed FCS/PLCP checksum are not returned, - * all other frames are returned without radiotap header - * if it was previously present. - * Also, frames with less than 16 bytes are dropped. - */ - skb = ieee80211_rx_monitor(local, skb, status); - if (!skb) { - rcu_read_unlock(); - return; - } - hdr = (struct ieee80211_hdr *) skb->data; memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; rx.u.rx.status = status; + rx.u.rx.load = load; + rx.u.rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - sta = rx.sta = sta_info_get(local, hdr->addr2); - if (sta) { + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) { rx.dev = rx.sta->dev; rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); } if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); + ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); goto end; } - if (unlikely(local->sta_scanning)) + if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; - skb = rx.skb; - - if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && - !atomic_read(&local->iff_promiscs) && - !is_multicast_ether_addr(hdr->addr1)) { - rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - rx.sta); - sta_info_put(sta); - rcu_read_unlock(); - return; - } + ieee80211_parse_qos(&rx); + ieee80211_verify_ip_alignment(&rx); - bssid = ieee80211_get_bssid(hdr, skb->len); + skb = rx.skb; list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) continue; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) + if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) continue; + bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; - prepres = prepare_for_handlers(sdata, bssid, &rx, hdr); - /* prepare_for_handlers can change sta */ - sta = rx.sta; + prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); - if (!prepres) + if (!prepares) continue; /* @@ -1536,27 +1837,266 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, prev->dev->name); continue; } - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + rx.fc = le16_to_cpu(hdr->frame_control); + ieee80211_invoke_rx_handlers(prev, &rx, skb_new); prev = sdata; } if (prev) { - rx.skb = skb; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + rx.fc = le16_to_cpu(hdr->frame_control); + ieee80211_invoke_rx_handlers(prev, &rx, skb); } else dev_kfree_skb(skb); end: - rcu_read_unlock(); + if (rx.sta) + sta_info_put(rx.sta); +} +#define SEQ_MODULO 0x1000 +#define SEQ_MASK 0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ + return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1)); +} + +static inline u16 seq_inc(u16 sq) +{ + return ((sq + 1) & SEQ_MASK); +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ + return ((sq1 - sq2) & SEQ_MASK); +} + + +/* + * As it function blongs to Rx path it must be called with + * the proper rcu_read_lock protection for its flow. + */ +u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb, u16 mpdu_seq_num, + int bar_req) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rx_status status; + u16 head_seq_num, buf_size; + int index; + u32 pkt_load; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + + buf_size = tid_agg_rx->buf_size; + head_seq_num = tid_agg_rx->head_seq_num; + + /* frame with out of date sequence number */ + if (seq_less(mpdu_seq_num, head_seq_num)) { + dev_kfree_skb(skb); + return 1; + } + + /* if frame sequence number exceeds our buffering window size or + * block Ack Request arrived - release stored frames */ + if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) { + /* new head to the ordering buffer */ + if (bar_req) + head_seq_num = mpdu_seq_num; + else + head_seq_num = + seq_inc(seq_sub(mpdu_seq_num, buf_size)); + /* release stored frames up to new head to stack */ + while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { + index = seq_sub(tid_agg_rx->head_seq_num, + tid_agg_rx->ssn) + % tid_agg_rx->buf_size; + + if (tid_agg_rx->reorder_buf[index]) { + /* release the reordered frames to stack */ + memcpy(&status, + tid_agg_rx->reorder_buf[index]->cb, + sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; + pkt_load = ieee80211_rx_load_stats(local, + tid_agg_rx->reorder_buf[index], + &status, rate); + __ieee80211_rx_handle_packet(hw, + tid_agg_rx->reorder_buf[index], + &status, pkt_load, rate); + tid_agg_rx->stored_mpdu_num--; + tid_agg_rx->reorder_buf[index] = NULL; + } + tid_agg_rx->head_seq_num = + seq_inc(tid_agg_rx->head_seq_num); + } + if (bar_req) + return 1; + } + + /* now the new frame is always in the range of the reordering */ + /* buffer window */ + index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) + % tid_agg_rx->buf_size; + /* check if we already stored this frame */ + if (tid_agg_rx->reorder_buf[index]) { + dev_kfree_skb(skb); + return 1; + } + + /* if arrived mpdu is in the right order and nothing else stored */ + /* release it immediately */ + if (mpdu_seq_num == tid_agg_rx->head_seq_num && + tid_agg_rx->stored_mpdu_num == 0) { + tid_agg_rx->head_seq_num = + seq_inc(tid_agg_rx->head_seq_num); + return 0; + } + + /* put the frame in the reordering buffer */ + tid_agg_rx->reorder_buf[index] = skb; + tid_agg_rx->stored_mpdu_num++; + /* release the buffer until next missing frame */ + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) + % tid_agg_rx->buf_size; + while (tid_agg_rx->reorder_buf[index]) { + /* release the reordered frame back to stack */ + memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, + sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; + pkt_load = ieee80211_rx_load_stats(local, + tid_agg_rx->reorder_buf[index], + &status, rate); + __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], + &status, pkt_load, rate); + tid_agg_rx->stored_mpdu_num--; + tid_agg_rx->reorder_buf[index] = NULL; + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); + index = seq_sub(tid_agg_rx->head_seq_num, + tid_agg_rx->ssn) % tid_agg_rx->buf_size; + } + return 1; +} + +static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct sta_info *sta; + struct tid_ampdu_rx *tid_agg_rx; + u16 fc, sc; + u16 mpdu_seq_num; + u8 ret = 0, *qc; + int tid; + + sta = sta_info_get(local, hdr->addr2); + if (!sta) + return ret; + + fc = le16_to_cpu(hdr->frame_control); + + /* filter the QoS data rx stream according to + * STA/TID and check if this STA/TID is on aggregation */ + if (!WLAN_FC_IS_QOS_DATA(fc)) + goto end_reorder; + + qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN; + tid = qc[0] & QOS_CONTROL_TID_MASK; + tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]); + + if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) + goto end_reorder; + + /* null data frames are excluded */ + if (unlikely(fc & IEEE80211_STYPE_NULLFUNC)) + goto end_reorder; + + /* new un-ordered ampdu frame - process it */ + + /* reset session timer */ + if (tid_agg_rx->timeout) { + unsigned long expires = + jiffies + (tid_agg_rx->timeout / 1000) * HZ; + mod_timer(&tid_agg_rx->session_timer, expires); + } + + /* if this mpdu is fragmented - terminate rx aggregation session */ + sc = le16_to_cpu(hdr->seq_ctrl); + if (sc & IEEE80211_SCTL_FRAG) { + ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, + tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); + ret = 1; + goto end_reorder; + } + + /* according to mpdu sequence number deal with reordering buffer */ + mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; + ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, + mpdu_seq_num, 0); +end_reorder: if (sta) sta_info_put(sta); + return ret; +} + +/* + * This is the receive path handler. It is called by a low level driver when an + * 802.11 MPDU is received from the hardware. + */ +void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_local *local = hw_to_local(hw); + u32 pkt_load; + struct ieee80211_rate *rate = NULL; + struct ieee80211_supported_band *sband; + + if (status->band < 0 || + status->band > IEEE80211_NUM_BANDS) { + WARN_ON(1); + return; + } + + sband = local->hw.wiphy->bands[status->band]; + + if (!sband || + status->rate_idx < 0 || + status->rate_idx >= sband->n_bitrates) { + WARN_ON(1); + return; + } + + rate = &sband->bitrates[status->rate_idx]; + + /* + * key references and virtual interfaces are protected using RCU + * and this requires that we are in a read-side RCU section during + * receive processing + */ + rcu_read_lock(); + + /* + * Frames with failed FCS/PLCP checksum are not returned, + * all other frames are returned without radiotap header + * if it was previously present. + * Also, frames with less than 16 bytes are dropped. + */ + skb = ieee80211_rx_monitor(local, skb, status, rate); + if (!skb) { + rcu_read_unlock(); + return; + } + + pkt_load = ieee80211_rx_load_stats(local, skb, status, rate); + local->channel_use_raw += pkt_load; + + if (!ieee80211_rx_reorder_ampdu(local, skb)) + __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate); + + rcu_read_unlock(); } EXPORT_SYMBOL(__ieee80211_rx); diff --git a/package/mac80211/src/net/mac80211/sta_info.c b/package/mac80211/src/net/mac80211/sta_info.c index 4ed1b60bb1..6b53783966 100644 --- a/package/mac80211/src/net/mac80211/sta_info.c +++ b/package/mac80211/src/net/mac80211/sta_info.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/if_arp.h> +#include <linux/timer.h> #include <net/mac80211.h> #include "ieee80211_i.h" @@ -73,36 +74,13 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) } EXPORT_SYMBOL(sta_info_get); -int sta_info_min_txrate_get(struct ieee80211_local *local) -{ - struct sta_info *sta; - struct ieee80211_hw_mode *mode; - int min_txrate = 9999999; - int i; - - read_lock_bh(&local->sta_lock); - mode = local->oper_hw_mode; - for (i = 0; i < STA_HASH_SIZE; i++) { - sta = local->sta_hash[i]; - while (sta) { - if (sta->txrate < min_txrate) - min_txrate = sta->txrate; - sta = sta->hnext; - } - } - read_unlock_bh(&local->sta_lock); - if (min_txrate == 9999999) - min_txrate = 0; - - return mode->rates[min_txrate].rate; -} - static void sta_info_release(struct kref *kref) { struct sta_info *sta = container_of(kref, struct sta_info, kref); struct ieee80211_local *local = sta->local; struct sk_buff *skb; + int i; /* free sta structure; it has already been removed from * hash table etc. external structures. Make sure that all @@ -115,6 +93,10 @@ static void sta_info_release(struct kref *kref) while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { dev_kfree_skb_any(skb); } + for (i = 0; i < STA_TID_NUM; i++) { + del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); + del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); kfree(sta); @@ -132,6 +114,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; + int i; + DECLARE_MAC_BUF(mac); sta = kzalloc(sizeof(*sta), gfp); if (!sta) @@ -150,6 +134,28 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; sta->dev = dev; + spin_lock_init(&sta->ampdu_mlme.ampdu_rx); + spin_lock_init(&sta->ampdu_mlme.ampdu_tx); + for (i = 0; i < STA_TID_NUM; i++) { + /* timer_to_tid must be initialized with identity mapping to + * enable session_timer's data differentiation. refer to + * sta_rx_agg_session_timer_expired for useage */ + sta->timer_to_tid[i] = i; + /* tid to tx queue: initialize according to HW (0 is valid) */ + sta->tid_to_tx_q[i] = local->hw.queues; + /* rx timers */ + sta->ampdu_mlme.tid_rx[i].session_timer.function = + sta_rx_agg_session_timer_expired; + sta->ampdu_mlme.tid_rx[i].session_timer.data = + (unsigned long)&sta->timer_to_tid[i]; + init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); + /* tx timers */ + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = + sta_addba_resp_timer_expired; + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = + (unsigned long)&sta->timer_to_tid[i]; + init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); __sta_info_get(sta); /* sta used by caller, decremented by @@ -158,14 +164,21 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), dev->ifindex, - STA_NOTIFY_ADD, addr); + if (local->ops->sta_notify) { + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) + sdata = sdata->u.vlan.ap; + + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_ADD, addr); + } write_unlock_bh(&local->sta_lock); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", - wiphy_name(local->hw.wiphy), MAC_ARG(addr)); + printk(KERN_DEBUG "%s: Added STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mac, addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS @@ -204,6 +217,7 @@ void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; + DECLARE_MAC_BUF(mac); might_sleep(); @@ -220,16 +234,24 @@ void sta_info_free(struct sta_info *sta) } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", - wiphy_name(local->hw.wiphy), MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: Removed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); sta->key = NULL; - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex, - STA_NOTIFY_REMOVE, sta->addr); + if (local->ops->sta_notify) { + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) + sdata = sdata->u.vlan.ap; + + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_REMOVE, sta->addr); + } rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); @@ -264,6 +286,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) return; @@ -282,7 +305,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (skb) { local->total_ps_buffered--; printk(KERN_DEBUG "Buffered frame expired (STA " - MAC_FMT ")\n", MAC_ARG(sta->addr)); + "%s)\n", print_mac(mac, sta->addr)); dev_kfree_skb(skb); } else break; @@ -303,7 +326,8 @@ static void sta_info_cleanup(unsigned long data) } read_unlock_bh(&local->sta_lock); - local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; + local->sta_cleanup.expires = + round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); add_timer(&local->sta_cleanup); } @@ -342,7 +366,8 @@ void sta_info_init(struct ieee80211_local *local) INIT_LIST_HEAD(&local->sta_list); init_timer(&local->sta_cleanup); - local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; + local->sta_cleanup.expires = + round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); local->sta_cleanup.data = (unsigned long) local; local->sta_cleanup.function = sta_info_cleanup; diff --git a/package/mac80211/src/net/mac80211/sta_info.h b/package/mac80211/src/net/mac80211/sta_info.h index 8f7ebe41c0..19f3fb4129 100644 --- a/package/mac80211/src/net/mac80211/sta_info.h +++ b/package/mac80211/src/net/mac80211/sta_info.h @@ -15,22 +15,110 @@ #include <linux/kref.h> #include "ieee80211_key.h" -/* Stations flags (struct sta_info::flags) */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_SHORT_PREAMBLE BIT(7) -/* whether this is an AP that we are associated with as a client */ -#define WLAN_STA_ASSOC_AP BIT(8) -#define WLAN_STA_WME BIT(9) -#define WLAN_STA_WDS BIT(27) +/** + * enum ieee80211_sta_info_flags - Stations flags + * + * These flags are used with &struct sta_info's @flags member. + * + * @WLAN_STA_AUTH: Station is authenticated. + * @WLAN_STA_ASSOC: Station is associated. + * @WLAN_STA_PS: Station is in power-save mode + * @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered) + * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. + * This bit is always checked so needs to be enabled for all stations + * when virtual port control is not in use. + * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble + * frames. + * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. + * @WLAN_STA_WME: Station is a QoS-STA. + * @WLAN_STA_WDS: Station is one of our WDS peers. + */ +enum ieee80211_sta_info_flags { + WLAN_STA_AUTH = 1<<0, + WLAN_STA_ASSOC = 1<<1, + WLAN_STA_PS = 1<<2, + WLAN_STA_TIM = 1<<3, + WLAN_STA_AUTHORIZED = 1<<4, + WLAN_STA_SHORT_PREAMBLE = 1<<5, + WLAN_STA_ASSOC_AP = 1<<6, + WLAN_STA_WME = 1<<7, + WLAN_STA_WDS = 1<<8, +}; + +#define STA_TID_NUM 16 +#define ADDBA_RESP_INTERVAL HZ +#define HT_AGG_MAX_RETRIES (0x3) +#define HT_AGG_STATE_INITIATOR_SHIFT (4) + +#define HT_ADDBA_REQUESTED_MSK BIT(0) +#define HT_ADDBA_DRV_READY_MSK BIT(1) +#define HT_ADDBA_RECEIVED_MSK BIT(2) +#define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3) +#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT) +#define HT_AGG_STATE_IDLE (0x0) +#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ + HT_ADDBA_DRV_READY_MSK | \ + HT_ADDBA_RECEIVED_MSK) + +/** + * struct tid_ampdu_tx - TID aggregation information (Tx). + * + * @state: TID's state in session state machine. + * @dialog_token: dialog token for aggregation session + * @ssn: Starting Sequence Number expected to be aggregated. + * @addba_resp_timer: timer for peer's response to addba request + * @addba_req_num: number of times addBA request has been sent. + */ +struct tid_ampdu_tx { + u8 state; + u8 dialog_token; + u16 ssn; + struct timer_list addba_resp_timer; + u8 addba_req_num; +}; + +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @state: TID's state in session state machine. + * @dialog_token: dialog token for aggregation session + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value. + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer + * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + */ +struct tid_ampdu_rx { + u8 state; + u8 dialog_token; + u16 ssn; + u16 buf_size; + u16 timeout; + u16 head_seq_num; + u16 stored_mpdu_num; + struct sk_buff **reorder_buf; + struct timer_list session_timer; +}; + +/** + * struct sta_ampdu_mlme - STA aggregation information. + * + * @tid_rx: aggregation info for Rx per TID + * @tid_tx: aggregation info for Tx per TID + * @ampdu_rx: for locking sections in aggregation Rx flow + * @ampdu_tx: for locking sectionsi in aggregation Tx flow + * @dialog_token_allocator: dialog token enumerator for each new session; + */ +struct sta_ampdu_mlme { + struct tid_ampdu_rx tid_rx[STA_TID_NUM]; + struct tid_ampdu_tx tid_tx[STA_TID_NUM]; + spinlock_t ampdu_rx; + spinlock_t ampdu_tx; + u8 dialog_token_allocator; +}; struct sta_info { struct kref kref; @@ -59,10 +147,11 @@ struct sta_info { unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ unsigned long last_rx; - u32 supp_rates; /* bitmap of supported rates in local->curr_rates */ - int txrate; /* index in local->curr_rates */ - int last_txrate; /* last rate used to send a frame to this STA */ - int last_nonerp_idx; + /* bitmap of supported rates per band */ + u64 supp_rates[IEEE80211_NUM_BANDS]; + int txrate_idx; + /* last rates used to send a frame to this STA */ + int last_txrate_idx, last_nonerp_txrate_idx; struct net_device *dev; /* which net device is this station associated * to */ @@ -99,6 +188,12 @@ struct sta_info { u16 listen_interval; + struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities + of this STA */ + struct sta_ampdu_mlme ampdu_mlme; + u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ + u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ + #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { struct dentry *dir; @@ -112,6 +207,7 @@ struct sta_info { struct dentry *wme_rx_queue; struct dentry *wme_tx_queue; #endif + struct dentry *agg_status; } debugfs; #endif }; @@ -141,7 +237,6 @@ static inline void __sta_info_get(struct sta_info *sta) } struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); -int sta_info_min_txrate_get(struct ieee80211_local *local); void sta_info_put(struct sta_info *sta); struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp); diff --git a/package/mac80211/src/net/mac80211/tkip.c b/package/mac80211/src/net/mac80211/tkip.c index 876cbe3710..3abe194e4d 100644 --- a/package/mac80211/src/net/mac80211/tkip.c +++ b/package/mac80211/src/net/mac80211/tkip.c @@ -276,9 +276,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, (iv32 == key->u.tkip.iv32_rx[queue] && iv16 <= key->u.tkip.iv16_rx[queue]))) { #ifdef CONFIG_TKIP_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " - MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - MAC_ARG(ta), + "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", + print_mac(mac, ta), iv32, iv16, key->u.tkip.iv32_rx[queue], key->u.tkip.iv16_rx[queue]); #endif /* CONFIG_TKIP_DEBUG */ @@ -300,8 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, #ifdef CONFIG_TKIP_DEBUG { int i; - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT - " TK=", MAC_ARG(ta)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" + " TK=", print_mac(mac, ta)); for (i = 0; i < 16; i++) printk("%02x ", key->conf.key[ diff --git a/package/mac80211/src/net/mac80211/tx.c b/package/mac80211/src/net/mac80211/tx.c index 957ec3c830..181d97015f 100644 --- a/package/mac80211/src/net/mac80211/tx.c +++ b/package/mac80211/src/net/mac80211/tx.c @@ -18,6 +18,7 @@ #include <linux/etherdevice.h> #include <linux/bitmap.h> #include <linux/rcupdate.h> +#include <net/net_namespace.h> #include <net/ieee80211_radiotap.h> #include <net/cfg80211.h> #include <net/mac80211.h> @@ -53,6 +54,7 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; int hdrlen; + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); if (skb->len < 4) { @@ -68,13 +70,13 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, printk(" FC=0x%04x DUR=0x%04x", fc, le16_to_cpu(hdr->duration_id)); if (hdrlen >= 10) - printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); + printk(" A1=%s", print_mac(mac, hdr->addr1)); if (hdrlen >= 16) - printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); if (hdrlen >= 24) - printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (hdrlen >= 30) - printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } #else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ @@ -90,9 +92,13 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, int rate, mrate, erp, dur, i; struct ieee80211_rate *txrate = tx->u.tx.rate; struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; + struct ieee80211_supported_band *sband; - erp = txrate->flags & IEEE80211_RATE_ERP; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + erp = 0; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = txrate->flags & IEEE80211_RATE_ERP_G; /* * data and mgmt (except PS Poll): @@ -148,20 +154,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps */ rate = -1; - mrate = 10; /* use 1 Mbps if everything fails */ - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > txrate->rate) - break; + /* use lowest available if everything fails */ + mrate = sband->bitrates[0].bitrate; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r = &sband->bitrates[i]; - if (IEEE80211_RATE_MODULATION(txrate->flags) != - IEEE80211_RATE_MODULATION(r->flags)) - continue; + if (r->bitrate > txrate->bitrate) + break; - if (r->flags & IEEE80211_RATE_BASIC) - rate = r->rate; - else if (r->flags & IEEE80211_RATE_MANDATORY) - mrate = r->rate; + if (tx->sdata->basic_rates & BIT(i)) + rate = r->bitrate; + + switch (sband->band) { + case IEEE80211_BAND_2GHZ: { + u32 flag; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + flag = IEEE80211_RATE_MANDATORY_G; + else + flag = IEEE80211_RATE_MANDATORY_B; + if (r->flags & flag) + mrate = r->bitrate; + break; + } + case IEEE80211_BAND_5GHZ: + if (r->flags & IEEE80211_RATE_MANDATORY_A) + mrate = r->bitrate; + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } } if (rate == -1) { /* No matching basic rate found; use highest suitable mandatory @@ -174,7 +196,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * to closest integer */ dur = ieee80211_frame_duration(local, 10, rate, erp, - tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); + tx->sdata->bss_conf.use_short_preamble); if (next_frag_len) { /* Frame is fragmented: duration increases with time needed to @@ -182,9 +204,8 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, dur *= 2; /* ACK + SIFS */ /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, - tx->sdata->flags & - IEEE80211_SDATA_SHORT_PREAMBLE); + txrate->bitrate, erp, + tx->sdata->bss_conf.use_short_preamble); } return dur; @@ -211,7 +232,7 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -221,58 +242,48 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) u32 sta_flags; if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; - if (unlikely(tx->local->sta_scanning != 0) && + if (unlikely(tx->local->sta_sw_scanning) && ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) - return TXRX_DROP; + return TX_DROP; if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) - return TXRX_CONTINUE; + return TX_CONTINUE; sta_flags = tx->sta ? tx->sta->flags : 0; if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS && + tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station " MAC_FMT "\n", - tx->dev->name, MAC_ARG(hdr->addr1)); + "associated station %s\n", + tx->dev->name, print_mac(mac, hdr->addr1)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); - return TXRX_DROP; + return TX_DROP; } } else { if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && tx->local->num_sta == 0 && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { + tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS)) { /* * No associated STAs - no need to send multicast * frames. */ - return TXRX_DROP; + return TX_DROP; } - return TXRX_CONTINUE; + return TX_CONTINUE; } - if (unlikely(/* !injected && */ tx->sdata->ieee802_1x && - !(sta_flags & WLAN_STA_AUTHORIZED))) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT - " (unauthorized port)\n", tx->dev->name, - MAC_ARG(hdr->addr1)); -#endif - I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); - return TXRX_DROP; - } - - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -280,7 +291,7 @@ ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) ieee80211_include_sequence(tx->sdata, hdr); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* This function is called whenever the AP is about to exceed the maximum limit @@ -302,7 +313,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) list_for_each_entry_rcu(sdata, &local->interfaces, list) { struct ieee80211_if_ap *ap; if (sdata->dev == local->mdev || - sdata->type != IEEE80211_IF_TYPE_AP) + sdata->vif.type != IEEE80211_IF_TYPE_AP) continue; ap = &sdata->u.ap; skb = skb_dequeue(&ap->ps_bc_buf); @@ -330,16 +341,27 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) wiphy_name(local->hw.wiphy), purged); } -static inline ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) { - /* broadcast/multicast frame */ - /* If any of the associated stations is in power save mode, - * the frame is buffered to be sent after DTIM beacon frame */ - if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && - tx->sdata->type != IEEE80211_IF_TYPE_WDS && - tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && - !(tx->fc & IEEE80211_FCTL_ORDER)) { + /* + * broadcast/multicast frame + * + * If any of the associated stations is in power save mode, + * the frame is buffered to be sent after DTIM beacon frame. + * This is done either by the hardware or us. + */ + + /* not AP/IBSS or ordered frame */ + if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) + return TX_CONTINUE; + + /* no stations in PS mode */ + if (!atomic_read(&tx->sdata->bss->num_sta_ps)) + return TX_CONTINUE; + + /* buffered in mac80211 */ + if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= @@ -353,28 +375,32 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) } else tx->local->total_ps_buffered++; skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } - return TXRX_CONTINUE; + /* buffered in hardware */ + tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + + return TX_CONTINUE; } -static inline ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta; + DECLARE_MAC_BUF(mac); if (unlikely(!sta || ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) - return TXRX_CONTINUE; + return TX_CONTINUE; if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " + printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", - MAC_ARG(sta->addr), sta->aid, + print_mac(mac, sta->addr), sta->aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->flags |= WLAN_STA_TIM; @@ -383,9 +409,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " + printk(KERN_DEBUG "%s: STA %s TX " "buffer full - dropping oldest frame\n", - tx->dev->name, MAC_ARG(sta->addr)); + tx->dev->name, print_mac(mac, sta->addr)); } dev_kfree_skb(old); } else @@ -401,26 +427,25 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; pkt_data->jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " + printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, - MAC_ARG(sta->addr)); + print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->pspoll = 0; - return TXRX_CONTINUE; + return TX_CONTINUE; } - -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) { if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (tx->flags & IEEE80211_TXRXD_TXUNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); @@ -428,13 +453,11 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) return ieee80211_tx_h_multicast_ps_buf(tx); } - - - -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { struct ieee80211_key *key; + u16 fc = tx->fc; if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) tx->key = NULL; @@ -443,23 +466,42 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { + !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && + !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); - return TXRX_DROP; - } else { + return TX_DROP; + } else tx->key = NULL; - tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - } if (tx->key) { + u16 ftype, stype; + tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ + + switch (tx->key->conf.alg) { + case ALG_WEP: + ftype = fc & IEEE80211_FCTL_FTYPE; + stype = fc & IEEE80211_FCTL_STYPE; + + if (ftype == IEEE80211_FTYPE_MGMT && + stype == IEEE80211_STYPE_AUTH) + break; + case ALG_TKIP: + case ALG_CCMP: + if (!WLAN_FC_DATA_PRESENT(fc)) + tx->key = NULL; + break; + } } - return TXRX_CONTINUE; + if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -471,14 +513,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) int frag_threshold = tx->local->fragmentation_threshold; if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; first = tx->skb; hdrlen = ieee80211_get_hdrlen(tx->fc); payload_len = first->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; - num_fragm = (payload_len + per_fragm - 1) / per_fragm; + num_fragm = DIV_ROUND_UP(payload_len, per_fragm); frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); if (!frags) @@ -525,7 +567,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) tx->u.tx.num_extra_frag = num_fragm - 1; tx->u.tx.extra_frag = frags; - return TXRX_CONTINUE; + return TX_CONTINUE; fail: printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); @@ -536,14 +578,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) kfree(frags); } I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) { if (!tx->key) - return TXRX_CONTINUE; + return TX_CONTINUE; switch (tx->key->conf.alg) { case ALG_WEP: @@ -556,63 +598,60 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) /* not reached */ WARN_ON(1); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) { - struct rate_control_extra extra; + struct rate_selection rsel; + struct ieee80211_supported_band *sband; - if (likely(!tx->u.tx.rate)) { - memset(&extra, 0, sizeof(extra)); - extra.mode = tx->u.tx.mode; - extra.ethertype = tx->ethertype; + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; - tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, - tx->skb, &extra); - if (unlikely(extra.probe != NULL)) { + if (likely(!tx->u.tx.rate)) { + rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); + tx->u.tx.rate = rsel.rate; + if (unlikely(rsel.probe)) { tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; - tx->u.tx.rate = extra.probe; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate; + tx->u.tx.rate = rsel.probe; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; if (!tx->u.tx.rate) - return TXRX_DROP; + return TX_DROP; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && - (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { + if (tx->sdata->bss_conf.use_cts_prot && + (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; - if (extra.probe) + if (rsel.probe) tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; else tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.rate = extra.nonerp; - tx->u.tx.control->rate = extra.nonerp; + tx->u.tx.rate = rsel.nonerp; + tx->u.tx.control->tx_rate = rsel.nonerp; tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->rate = tx->u.tx.rate; + tx->u.tx.control->tx_rate = tx->u.tx.rate; } - tx->u.tx.control->tx_rate = tx->u.tx.rate->val; + tx->u.tx.control->tx_rate = tx->u.tx.rate; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -639,16 +678,16 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ - if (mode->mode == MODE_IEEE80211G && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && + if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && + (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TXRXD_TXUNICAST) && - (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && + tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; @@ -656,10 +695,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && + tx->sdata->bss_conf.use_short_preamble && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration @@ -672,19 +711,33 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate, *baserate; + int idx; + + sband = tx->local->hw.wiphy->bands[ + tx->local->hw.conf.channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = tx->u.tx.rate; - while (rate > mode->rates && - !(rate->flags & IEEE80211_RATE_BASIC)) - rate--; + baserate = NULL; - control->rts_cts_rate = rate->val; - control->rts_rate = rate; + for (idx = 0; idx < sband->n_bitrates; idx++) { + if (sband->bitrates[idx].bitrate > rate->bitrate) + continue; + if (tx->sdata->basic_rates & BIT(idx) && + (!baserate || + (baserate->bitrate < sband->bitrates[idx].bitrate))) + baserate = &sband->bitrates[idx]; + } + + if (baserate) + control->rts_cts_rate = baserate; + else + control->rts_cts_rate = &sband->bitrates[0]; } if (tx->sta) { @@ -701,26 +754,17 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } } - /* - * Tell hardware to not encrypt when we had sw crypto. - * Because we use the same flag to internally indicate that - * no (software) encryption should be done, we have to set it - * after all crypto handlers. - */ - if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) { struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; + struct ieee80211_rate *rate = tx->u.tx.rate; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -731,9 +775,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) + if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ || + (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -747,14 +791,15 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) load += hdrtime; - load += skb->len * tx->u.tx.rate->rate_inv; + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { load += 2 * hdrtime; load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->rate; + tx->u.tx.rate->bitrate; } } @@ -765,13 +810,12 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) tx->sta->channel_use_raw += load; tx->sdata->channel_use_raw += load; - return TXRX_CONTINUE; + return TX_CONTINUE; } -/* TODO: implement register/unregister functions for adding TX/RX handlers - * into ordered list */ -ieee80211_tx_handler ieee80211_tx_handlers[] = +typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *); +static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, ieee80211_tx_h_sequence, @@ -792,7 +836,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { @@ -807,10 +851,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; + struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->u.tx.control; + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TXRXD_TX_INJECTED; tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; @@ -843,10 +889,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps */ target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r; - if (r->rate == target_rate) { + r = &sband->bitrates[i]; + + if (r->bitrate == target_rate) { tx->u.tx.rate = r; break; } @@ -861,9 +909,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, control->antenna_sel_tx = (*iterator.this_arg) + 1; break; +#if 0 case IEEE80211_RADIOTAP_DBM_TX_POWER: control->power_level = *iterator.this_arg; break; +#endif case IEEE80211_RADIOTAP_FLAGS: if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { @@ -875,7 +925,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TXRX_DROP; + return TX_DROP; skb_trim(skb, skb->len - FCS_LEN); } @@ -898,7 +948,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TXRX_DROP; + return TX_DROP; /* * remove the radiotap header @@ -907,13 +957,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, */ skb_pull(skb, iterator.max_length); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* * initialises @tx */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *dev, @@ -922,7 +972,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; - ieee80211_txrx_result res = TXRX_CONTINUE; int hdrlen; @@ -940,9 +989,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) - return TXRX_DROP; + if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) { + if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + return TX_DROP; /* * __ieee80211_parse_tx_radiotap has now removed @@ -987,12 +1036,10 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - return res; + return TX_CONTINUE; } -/* Device in tx->dev has a reference added; use dev_put(tx->dev) when - * finished with it. - * +/* * NB: @tx is uninitialised when passed in here */ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, @@ -1004,7 +1051,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct net_device *dev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(pkt_data->ifindex); + dev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1013,6 +1060,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, return -ENODEV; /* initialises tx with control */ __ieee80211_tx_prepare(tx, skb, dev, control); + dev_put(dev); return 0; } @@ -1047,8 +1095,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_hwrate; - control->rate = tx->u.tx.last_frag_rate; + control->tx_rate = tx->u.tx.last_frag_rate; + if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; @@ -1082,7 +1130,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; + ieee80211_tx_result res = TX_DROP, res_prepare; int ret, i; WARN_ON(__ieee80211_queue_pending(local, control->queue)); @@ -1095,7 +1143,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - if (res_prepare == TXRX_DROP) { + if (res_prepare == TX_DROP) { dev_kfree_skb(skb); return 0; } @@ -1107,12 +1155,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); sta = tx.sta; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res != TXRX_CONTINUE) + if (res != TX_CONTINUE) break; } @@ -1121,12 +1169,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, if (sta) sta_info_put(sta); - if (unlikely(res == TXRX_DROP)) { + if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); goto drop; } - if (unlikely(res == TXRX_QUEUED)) { + if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); rcu_read_unlock(); return 0; @@ -1144,7 +1192,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, } else { next_len = 0; tx.u.tx.rate = tx.u.tx.last_frag_rate; - tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1181,7 +1228,6 @@ retry: store->skb = skb; store->extra_frag = tx.u.tx.extra_frag; store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; store->last_frag_rate = tx.u.tx.last_frag_rate; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); @@ -1219,7 +1265,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, memset(&control, 0, sizeof(struct ieee80211_tx_control)); if (pkt_data->ifindex) - odev = dev_get_by_index(pkt_data->ifindex); + odev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1243,14 +1289,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, } } - control.ifindex = odev->ifindex; - control.type = osdata->type; + control.vif = &osdata->vif; + control.type = osdata->vif.type; if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) control.flags |= IEEE80211_TXCTL_REQUEUE; + if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) + control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; + if (pkt_data->flags & IEEE80211_TXPD_AMPDU) + control.flags |= IEEE80211_TXCTL_AMPDU; control.queue = pkt_data->queue; ret = ieee80211_tx(odev, skb, &control); @@ -1343,6 +1393,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, int encaps_len, skip_header_bytes; int nh_pos, h_pos; struct sta_info *sta; + u32 sta_flags = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(skb->len < ETH_HLEN)) { @@ -1358,10 +1409,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ ethertype = (skb->data[12] << 8) | skb->data[13]; - /* TODO: handling for 802.1x authorized/unauthorized port */ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - switch (sdata->type) { + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_AP: case IEEE80211_IF_TYPE_VLAN: fc |= IEEE80211_FCTL_FROMDS; @@ -1400,14 +1450,47 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - /* receiver is QoS enabled, use a QoS type frame */ - sta = sta_info_get(local, hdr.addr1); - if (sta) { - if (sta->flags & WLAN_STA_WME) { - fc |= IEEE80211_STYPE_QOS_DATA; - hdrlen += 2; + /* + * There's no need to try to look up the destination + * if it is a multicast address (which can only happen + * in AP mode) + */ + if (!is_multicast_ether_addr(hdr.addr1)) { + sta = sta_info_get(local, hdr.addr1); + if (sta) { + sta_flags = sta->flags; + sta_info_put(sta); } - sta_info_put(sta); + } + + /* receiver is QoS enabled, use a QoS type frame */ + if (sta_flags & WLAN_STA_WME) { + fc |= IEEE80211_STYPE_QOS_DATA; + hdrlen += 2; + } + + /* + * Drop unicast frames to unauthorised stations unless they are + * EAPOL frames from the local station. + */ + if (unlikely(!is_multicast_ether_addr(hdr.addr1) && + !(sta_flags & WLAN_STA_AUTHORIZED) && + !(ethertype == ETH_P_PAE && + compare_ether_addr(dev->dev_addr, + skb->data + ETH_ALEN) == 0))) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); + + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped frame to %s" + " (unauthorized port)\n", dev->name, + print_mac(mac, hdr.addr1)); +#endif + + I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); + + ret = 0; + goto fail; } hdr.frame_control = cpu_to_le16(fc); @@ -1498,6 +1581,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = dev->ifindex; + if (ethertype == ETH_P_PAE) + pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1522,64 +1607,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, return ret; } -/* - * This is the transmit routine for the 802.11 type interfaces - * called by upper layers of the linux networking - * stack when it has a frame to transmit - */ -int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_hdr *hdr; - u16 fc; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (skb->len < 10) { - dev_kfree_skb(skb); - return 0; - } - - if (skb_headroom(skb) < sdata->local->tx_headroom) { - if (pskb_expand_head(skb, sdata->local->tx_headroom, - 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return 0; - } - } - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; - - skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ - skb->dev = sdata->local->mdev; - - /* - * We're using the protocol field of the the frame control header - * to request TX callback for hostapd. BIT(1) is checked. - */ - if ((fc & BIT(1)) == BIT(1)) { - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; - fc &= ~BIT(1); - hdr->frame_control = cpu_to_le16(fc); - } - - if (!(fc & IEEE80211_FCTL_PROTECTED)) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - dev_queue_xmit(skb); - - return 0; -} - /* helper functions for pending packets for when queues are stopped */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) @@ -1619,7 +1646,6 @@ void ieee80211_tx_pending(unsigned long data) tx.u.tx.control = &store->control; tx.u.tx.extra_frag = store->extra_frag; tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; tx.u.tx.last_frag_rate = store->last_frag_rate; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) @@ -1648,7 +1674,8 @@ void ieee80211_tx_pending(unsigned long data) static void ieee80211_beacon_add_tim(struct ieee80211_local *local, struct ieee80211_if_ap *bss, - struct sk_buff *skb) + struct sk_buff *skb, + struct beacon_data *beacon) { u8 *pos, *tim; int aid0 = 0; @@ -1664,7 +1691,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, IEEE80211_MAX_AID+1); if (bss->dtim_count == 0) - bss->dtim_count = bss->dtim_period - 1; + bss->dtim_count = beacon->dtim_period - 1; else bss->dtim_count--; @@ -1672,7 +1699,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = bss->dtim_count; - *pos++ = bss->dtim_period; + *pos++ = beacon->dtim_period; if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) aid0 = 1; @@ -1710,7 +1737,8 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, read_unlock_bh(&local->sta_lock); } -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, +struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_tx_control *control) { struct ieee80211_local *local = hw_to_local(hw); @@ -1718,81 +1746,81 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; - struct ieee80211_rate *rate; - struct rate_control_extra extra; - u8 *b_head, *b_tail; - int bh_len, bt_len; - - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - ap = &sdata->u.ap; - dev_put(bdev); - } + struct rate_selection rsel; + struct beacon_data *beacon; + struct ieee80211_supported_band *sband; - if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || - !ap->beacon_head) { + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + rcu_read_lock(); + + sdata = vif_to_sdata(vif); + bdev = sdata->dev; + ap = &sdata->u.ap; + + beacon = rcu_dereference(ap->beacon); + + if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for idx=%d " - "(%s)\n", if_id, bdev ? bdev->name : "N/A"); + printk(KERN_DEBUG "no beacon data avail for %s\n", + bdev->name); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - return NULL; + skb = NULL; + goto out; } - /* Assume we are generating the normal beacon locally */ - b_head = ap->beacon_head; - b_tail = ap->beacon_tail; - bh_len = ap->beacon_head_len; - bt_len = ap->beacon_tail_len; - - skb = dev_alloc_skb(local->tx_headroom + - bh_len + bt_len + 256 /* maximum TIM len */); + /* headroom, head length, tail length and maximum TIM length */ + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + + beacon->tail_len + 256); if (!skb) - return NULL; + goto out; skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, bh_len), b_head, bh_len); + memcpy(skb_put(skb, beacon->head_len), beacon->head, + beacon->head_len); ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - ieee80211_beacon_add_tim(local, ap, skb); + ieee80211_beacon_add_tim(local, ap, skb, beacon); - if (b_tail) { - memcpy(skb_put(skb, bt_len), b_tail, bt_len); - } + if (beacon->tail) + memcpy(skb_put(skb, beacon->tail_len), beacon->tail, + beacon->tail_len); if (control) { - memset(&extra, 0, sizeof(extra)); - extra.mode = local->oper_hw_mode; - - rate = rate_control_get_rate(local, local->mdev, skb, &extra); - if (!rate) { + rate_control_get_rate(local->mdev, sband, skb, &rsel); + if (!rsel.rate) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " - "found\n", wiphy_name(local->hw.wiphy)); + printk(KERN_DEBUG "%s: ieee80211_beacon_get: " + "no rate found\n", + wiphy_name(local->hw.wiphy)); } dev_kfree_skb(skb); - return NULL; + skb = NULL; + goto out; } - control->tx_rate = - ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rate->val2 : rate->val; + control->vif = vif; + control->tx_rate = rsel.rate; + if (sdata->bss_conf.use_short_preamble && + rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->power_level = local->hw.conf.power_level; control->flags |= IEEE80211_TXCTL_NO_ACK; control->retry_limit = 1; control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; } ap->num_beacons++; + + out: + rcu_read_unlock(); return skb; } EXPORT_SYMBOL(ieee80211_beacon_get); -void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, +void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts) @@ -1802,13 +1830,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; rts->frame_control = cpu_to_le16(fctl); - rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl); + rts->duration = ieee80211_rts_duration(hw, vif, frame_len, + frame_txctl); memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); } EXPORT_SYMBOL(ieee80211_rts_get); -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts) @@ -1818,13 +1847,15 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; cts->frame_control = cpu_to_le16(fctl); - cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl); + cts->duration = ieee80211_ctstoself_duration(hw, vif, + frame_len, frame_txctl); memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); } EXPORT_SYMBOL(ieee80211_ctstoself_get); struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_tx_control *control) { struct ieee80211_local *local = hw_to_local(hw); @@ -1832,19 +1863,28 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP; + ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; + struct beacon_data *beacon; - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - bss = &sdata->u.ap; - dev_put(bdev); - } - if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) + sdata = vif_to_sdata(vif); + bdev = sdata->dev; + + + if (!bss) + return NULL; + + rcu_read_lock(); + beacon = rcu_dereference(bss->beacon); + + if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || + !beacon->head) { + rcu_read_unlock(); return NULL; + } + rcu_read_unlock(); if (bss->dtim_count != 0) return NULL; /* send buffered bc/mc only after DTIM beacon */ @@ -1871,21 +1911,20 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, } sta = tx.sta; tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; handler++) { + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res == TXRX_DROP || res == TXRX_QUEUED) + if (res == TX_DROP || res == TX_QUEUED) break; } - dev_put(tx.dev); skb = tx.skb; /* handlers are allowed to change skb */ - if (res == TXRX_DROP) { + if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); dev_kfree_skb(skb); skb = NULL; - } else if (res == TXRX_QUEUED) { + } else if (res == TX_QUEUED) { I802_DEBUG_INC(local->tx_handlers_queued); skb = NULL; } diff --git a/package/mac80211/src/net/mac80211/util.c b/package/mac80211/src/net/mac80211/util.c index 27203f1b95..f64804fed0 100644 --- a/package/mac80211/src/net/mac80211/util.c +++ b/package/mac80211/src/net/mac80211/util.c @@ -20,7 +20,9 @@ #include <linux/if_arp.h> #include <linux/wireless.h> #include <linux/bitmap.h> +#include <net/net_namespace.h> #include <net/cfg80211.h> +#include <net/rtnetlink.h> #include "ieee80211_i.h" #include "ieee80211_rate.h" @@ -38,108 +40,22 @@ const unsigned char rfc1042_header[] = const unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ -static const unsigned char eapol_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; - -static int rate_list_match(const int *rate_list, int rate) -{ - int i; - - if (!rate_list) - return 0; - - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; - - return 0; -} - -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; - } -} - -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, + enum ieee80211_if_types type) { u16 fc; - if (len < 24) + /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ + if (len < 16) return NULL; fc = le16_to_cpu(hdr->frame_control); switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: + if (len < 24) /* drop incorrect hdr len (data) */ + return NULL; switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case IEEE80211_FCTL_TODS: return hdr->addr1; @@ -152,10 +68,24 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) } break; case IEEE80211_FTYPE_MGMT: + if (len < 24) /* drop incorrect hdr len (mgmt) */ + return NULL; return hdr->addr3; case IEEE80211_FTYPE_CTL: if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) return hdr->addr1; + else if ((fc & IEEE80211_FCTL_STYPE) == + IEEE80211_STYPE_BACK_REQ) { + switch (type) { + case IEEE80211_IF_TYPE_STA: + return hdr->addr2; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_VLAN: + return hdr->addr1; + default: + return NULL; + } + } else return NULL; } @@ -216,31 +146,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -int ieee80211_is_eapol(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr; - u16 fc; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - - hdr = (const struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return 0; - - hdrlen = ieee80211_get_hdrlen(fc); - - if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && - memcmp(skb->data + hdrlen, eapol_header, - sizeof(eapol_header)) == 0)) - return 1; - - return 0; -} - void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -271,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, * DIV_ROUND_UP() operations. */ - if (local->hw.conf.phymode == MODE_IEEE80211A || erp) { + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { /* * OFDM: * @@ -311,120 +216,92 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, } /* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, - size_t frame_len, int rate) +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + size_t frame_len, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); - struct net_device *bdev = dev_get_by_index(if_id); - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); u16 dur; int erp; - if (unlikely(!bdev)) - return 0; + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, - erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, + sdata->bss_conf.use_short_preamble); - dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_generic_frame_duration); -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, - size_t frame_len, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); - struct ieee80211_sub_if_data *sdata; - int short_preamble; + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + bool short_preamble; int erp; u16 dur; - if (unlikely(!bdev)) - return 0; + short_preamble = sdata->bss_conf.use_short_preamble; - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; + rate = frame_txctl->rts_cts_rate; - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, + dur = ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, + dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); - dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_rts_duration); -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); - struct ieee80211_sub_if_data *sdata; - int short_preamble; + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + bool short_preamble; int erp; u16 dur; - if (unlikely(!bdev)) - return 0; + short_preamble = sdata->bss_conf.use_short_preamble; - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + rate = frame_txctl->rts_cts_rate; + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); } - dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} - void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); @@ -483,3 +360,37 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) ieee80211_wake_queue(hw, i); } EXPORT_SYMBOL(ieee80211_wake_queues); + +void ieee80211_iterate_active_interfaces( + struct ieee80211_hw *hw, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_INVALID: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_VLAN: + continue; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_WDS: + break; + } + if (sdata->dev == local->mdev) + continue; + if (netif_running(sdata->dev)) + iterator(data, sdata->dev->dev_addr, + &sdata->vif); + } + + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); diff --git a/package/mac80211/src/net/mac80211/wep.c b/package/mac80211/src/net/mac80211/wep.c index 6675261e95..a33ef5cfa9 100644 --- a/package/mac80211/src/net/mac80211/wep.c +++ b/package/mac80211/src/net/mac80211/wep.c @@ -16,7 +16,7 @@ #include <linux/crypto.h> #include <linux/err.h> #include <linux/mm.h> -#include <asm/scatterlist.h> +#include <linux/scatterlist.h> #include <net/mac80211.h> #include "ieee80211_i.h" @@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, *icv = cpu_to_le32(~crc32_le(~0, data, data_len)); crypto_blkcipher_setkey(tfm, rc4key, klen); - sg.page = virt_to_page(data); - sg.offset = offset_in_page(data); - sg.length = data_len + WEP_ICV_LEN; + sg_init_one(&sg, data, data_len + WEP_ICV_LEN); crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); } @@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, __le32 crc; crypto_blkcipher_setkey(tfm, rc4key, klen); - sg.page = virt_to_page(data); - sg.offset = offset_in_page(data); - sg.length = data_len + WEP_ICV_LEN; + sg_init_one(&sg, data, data_len + WEP_ICV_LEN); crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); crc = cpu_to_le32(~crc32_le(~0, data, data_len)); @@ -269,7 +265,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, skb->data + hdrlen + WEP_IV_LEN, len)) { - printk(KERN_DEBUG "WEP decrypt failed (ICV)\n"); + if (net_ratelimit()) + printk(KERN_DEBUG "WEP decrypt failed (ICV)\n"); ret = -1; } @@ -308,20 +305,22 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) return NULL; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) { if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { +#ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); - return TXRX_DROP; +#endif /* CONFIG_MAC80211_DEBUG */ + return RX_DROP_UNUSABLE; } } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); @@ -329,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) skb_trim(rx->skb, rx->skb->len - 4); } - return TXRX_CONTINUE; + return RX_CONTINUE; } static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) @@ -347,26 +346,16 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return 0; } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; - - fc = le16_to_cpu(hdr->frame_control); - - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) - return TXRX_CONTINUE; - tx->u.tx.control->iv_len = WEP_IV_LEN; tx->u.tx.control->icv_len = WEP_ICV_LEN; ieee80211_tx_set_iswep(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } if (tx->u.tx.extra_frag) { @@ -375,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { I802_DEBUG_INC(tx->local-> tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } } } - return TXRX_CONTINUE; + return TX_CONTINUE; } diff --git a/package/mac80211/src/net/mac80211/wep.h b/package/mac80211/src/net/mac80211/wep.h index 785fbb4e0d..43aef50cd0 100644 --- a/package/mac80211/src/net/mac80211/wep.h +++ b/package/mac80211/src/net/mac80211/wep.h @@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); #endif /* WEP_H */ diff --git a/package/mac80211/src/net/mac80211/wme.c b/package/mac80211/src/net/mac80211/wme.c index 5b8a157975..7bbc79371d 100644 --- a/package/mac80211/src/net/mac80211/wme.c +++ b/package/mac80211/src/net/mac80211/wme.c @@ -19,15 +19,19 @@ #include "wme.h" /* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 8 +#define TC_80211_MAX_QUEUES 16 + +const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { + unsigned long qdisc_pool; struct tcf_proto *filter_list; struct Qdisc *queues[TC_80211_MAX_QUEUES]; struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; }; +static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; /* given a data frame determine the 802.1p/1d tag to use */ static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd) @@ -54,12 +58,12 @@ static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd) return skb->priority - 256; /* check there is a valid IP header present */ - offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */; - if (skb->protocol != __constant_htons(ETH_P_IP) || - skb->len < offset + sizeof(*ip)) + offset = ieee80211_get_hdrlen_from_skb(skb); + if (skb->len < offset + sizeof(llc_ip_hdr) + sizeof(*ip) || + memcmp(skb->data + offset, llc_ip_hdr, sizeof(llc_ip_hdr))) return 0; - ip = (struct iphdr *) (skb->data + offset); + ip = (struct iphdr *) (skb->data + offset + sizeof(llc_ip_hdr)); dscp = ip->tos & 0xfc; if (dscp & 0x1c) @@ -97,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; - const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; /* see if frame is data or non data frame */ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { @@ -145,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; int err, queue; + struct sta_info *sta; + u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - skb_queue_tail(&q->requeued[pkt_data->queue], skb); + queue = pkt_data->queue; + sta = sta_info_get(local, hdr->addr1); + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, &q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } + skb_queue_tail(&q->requeued[queue], skb); qd->q.qlen++; return 0; } @@ -158,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) */ if (WLAN_FC_IS_QOS_DATA(fc)) { u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2; - u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK; + u8 ack_policy = 0; + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (local->wifi_wme_noack_test) - qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK << + ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ - *p = qos_hdr; + *p = ack_policy | tid; p++; *p = 0; + + sta = sta_info_get(local, hdr->addr1); + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, &q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } } if (unlikely(queue >= local->hw.queues)) { @@ -183,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) kfree_skb(skb); err = NET_XMIT_DROP; } else { + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; pkt_data->queue = (unsigned int) queue; qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); @@ -234,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < hw->queues; queue++) { /* see if there is room in this hardware queue */ - if (test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue]) || - test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) + if ((test_bit(IEEE80211_LINK_STATE_XOFF, + &local->state[queue])) || + (test_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[queue])) || + (!test_bit(queue, &q->qdisc_pool))) continue; /* there is space - try and get a frame */ @@ -359,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt) } } + /* reserve all legacy QoS queues */ + for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) + set_bit(i, &q->qdisc_pool); + return err; } @@ -604,3 +643,80 @@ void ieee80211_wme_unregister(void) { unregister_qdisc(&wme_qdisc_ops); } + +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + int i; + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + DECLARE_MAC_BUF(mac); + + /* prepare the filter and save it for the SW queue + * matching the recieved HW queue */ + + /* try to get a Qdisc from the pool */ + for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) + if (!test_and_set_bit(i, &q->qdisc_pool)) { + ieee80211_stop_queue(local_to_hw(local), i); + sta->tid_to_tx_q[tid] = i; + + /* IF there are already pending packets + * on this tid first we need to drain them + * on the previous queue + * since HT is strict in order */ +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "allocated aggregation queue" + " %d tid %d addr %s pool=0x%lX\n", + i, tid, print_mac(mac, sta->addr), + q->qdisc_pool); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + return 0; + } + + return -EAGAIN; +} + +/** + * the caller needs to hold local->mdev->queue_lock + */ +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + int agg_queue = sta->tid_to_tx_q[tid]; + + /* return the qdisc to the pool */ + clear_bit(agg_queue, &q->qdisc_pool); + sta->tid_to_tx_q[tid] = local->hw.queues; + + if (requeue) + ieee80211_requeue(local, agg_queue); + else + q->queues[agg_queue]->ops->reset(q->queues[agg_queue]); +} + +void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ + struct Qdisc *root_qd = local->mdev->qdisc_sleeping; + struct ieee80211_sched_data *q = qdisc_priv(root_qd); + struct Qdisc *qdisc = q->queues[queue]; + struct sk_buff *skb = NULL; + u32 len = qdisc->q.qlen; + + if (!qdisc || !qdisc->dequeue) + return; + + printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen); + for (len = qdisc->q.qlen; len > 0; len--) { + skb = qdisc->dequeue(qdisc); + root_qd->q.qlen--; + /* packet will be classified again and */ + /* skb->packet_data->queue will be overridden if needed */ + if (skb) + wme_qdiscop_enqueue(skb, root_qd); + } +} diff --git a/package/mac80211/src/net/mac80211/wme.h b/package/mac80211/src/net/mac80211/wme.h index 76c713a645..fcc6b05508 100644 --- a/package/mac80211/src/net/mac80211/wme.h +++ b/package/mac80211/src/net/mac80211/wme.h @@ -24,6 +24,8 @@ #define QOS_CONTROL_TAG1D_MASK 0x07 +extern const int ieee802_1d_to_ac[8]; + static inline int WLAN_FC_IS_QOS_DATA(u16 fc) { return (fc & 0x8C) == 0x88; @@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) #ifdef CONFIG_NET_SCHED void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); - +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid); +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue); +void ieee80211_requeue(struct ieee80211_local *local, int queue); int ieee80211_wme_register(void); void ieee80211_wme_unregister(void); #else @@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev) { return 0; } - +static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + return -EAGAIN; +} +static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ +} +static inline void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ +} static inline int ieee80211_wme_register(void) { return 0; diff --git a/package/mac80211/src/net/mac80211/wpa.c b/package/mac80211/src/net/mac80211/wpa.c index 0b32ab64eb..b35e51c6ce 100644 --- a/package/mac80211/src/net/mac80211/wpa.c +++ b/package/mac80211/src/net/mac80211/wpa.c @@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) { u8 *data, *sa, *da, *key, *mic, qos_tid; @@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) - return TXRX_DROP; + return TX_DROP; if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && @@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ - return TXRX_CONTINUE; + return TX_CONTINUE; } if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { @@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) GFP_ATOMIC))) { printk(KERN_DEBUG "%s: failed to allocate more memory " "for Michael MIC\n", tx->dev->name); - return TXRX_DROP; + return TX_DROP; } } @@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) mic = skb_put(skb, MICHAEL_MIC_LEN); michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) { u8 *data, *sa, *da, *key = NULL, qos_tid; @@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; + DECLARE_MAC_BUF(mac); fc = rx->fc; @@ -139,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) * No way to verify the MIC if the hardware stripped it */ if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) - return TXRX_DROP; + return RX_DROP_UNUSABLE; data_len -= MICHAEL_MIC_LEN; @@ -161,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " - MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); + "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } /* remove Michael MIC from payload */ @@ -178,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -241,19 +242,12 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; struct sk_buff *skb = tx->skb; int wpa_test = 0, test = 0; - fc = le16_to_cpu(hdr->frame_control); - - if (!WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; - tx->u.tx.control->icv_len = TKIP_ICV_LEN; tx->u.tx.control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_iswep(tx); @@ -263,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (tkip_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -290,15 +284,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { @@ -307,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) * replay protection, and stripped the ICV/IV so * we cannot do any checks here. */ - return TXRX_CONTINUE; + return RX_CONTINUE; } /* let TKIP code verify IV, but skip decryption */ @@ -321,10 +316,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) &rx->u.rx.tkip_iv32, &rx->u.rx.tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { - printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from " - MAC_FMT " (res=%d)\n", - rx->dev->name, MAC_ARG(rx->sta->addr), res); - return TXRX_DROP; +#ifdef CONFIG_MAC80211_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: TKIP decrypt failed for RX " + "frame from %s (res=%d)\n", rx->dev->name, + print_mac(mac, rx->sta->addr), res); +#endif /* CONFIG_MAC80211_DEBUG */ + return RX_DROP_UNUSABLE; } /* Trim ICV */ @@ -334,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen); skb_pull(skb, TKIP_IV_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -493,19 +491,12 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; struct sk_buff *skb = tx->skb; int test = 0; - fc = le16_to_cpu(hdr->frame_control); - - if (!WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; - tx->u.tx.control->icv_len = CCMP_MIC_LEN; tx->u.tx.control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_iswep(tx); @@ -515,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -544,35 +535,37 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) struct sk_buff *skb = rx->skb; u8 pn[CCMP_PN_LEN]; int data_len; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; if (!rx->sta || data_len < 0) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { #ifdef CONFIG_MAC80211_DEBUG u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; + printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " - MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " + "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name, - MAC_ARG(rx->sta->addr), + print_mac(mac, rx->sta->addr), pn[0], pn[1], pn[2], pn[3], pn[4], pn[5], ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ key->u.ccmp.replays++; - return TXRX_DROP; + return RX_DROP_UNUSABLE; } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { @@ -590,10 +583,13 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) skb->data + hdrlen + CCMP_HDR_LEN, data_len, skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) { - printk(KERN_DEBUG "%s: CCMP decrypt failed for RX " - "frame from " MAC_FMT "\n", rx->dev->name, - MAC_ARG(rx->sta->addr)); - return TXRX_DROP; +#ifdef CONFIG_MAC80211_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: CCMP decrypt failed " + "for RX frame from %s\n", rx->dev->name, + print_mac(mac, rx->sta->addr)); +#endif /* CONFIG_MAC80211_DEBUG */ + return RX_DROP_UNUSABLE; } } @@ -604,6 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); skb_pull(skb, CCMP_HDR_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } - diff --git a/package/mac80211/src/net/mac80211/wpa.h b/package/mac80211/src/net/mac80211/wpa.h index 49d80cf0cd..16e4dba4aa 100644 --- a/package/mac80211/src/net/mac80211/wpa.h +++ b/package/mac80211/src/net/mac80211/wpa.h @@ -13,19 +13,19 @@ #include <linux/types.h> #include "ieee80211_i.h" -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); #endif /* WPA_H */ diff --git a/package/mac80211/src/net/wireless/Kconfig b/package/mac80211/src/net/wireless/Kconfig index 6291f13bba..79270903bd 100644 --- a/package/mac80211/src/net/wireless/Kconfig +++ b/package/mac80211/src/net/wireless/Kconfig @@ -3,16 +3,16 @@ config CFG80211 config NL80211 bool "nl80211 new netlink interface support" - depends CFG80211 + depends on CFG80211 default y ---help--- - This option turns on the new netlink interface - (nl80211) support in cfg80211. + This option turns on the new netlink interface + (nl80211) support in cfg80211. - If =n, drivers using mac80211 will be configured via - wireless extension support provided by that subsystem. + If =n, drivers using mac80211 will be configured via + wireless extension support provided by that subsystem. - If unsure, say Y. + If unsure, say Y. config WIRELESS_EXT bool "Wireless extensions" diff --git a/package/mac80211/src/net/wireless/Makefile b/package/mac80211/src/net/wireless/Makefile index 5664c2cfd7..b9f943c45f 100644 --- a/package/mac80211/src/net/wireless/Makefile +++ b/package/mac80211/src/net/wireless/Makefile @@ -1,4 +1,5 @@ +obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o -cfg80211-y += core.o sysfs.o radiotap.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o cfg80211-$(CONFIG_NL80211) += nl80211.o diff --git a/package/mac80211/src/net/wireless/core.c b/package/mac80211/src/net/wireless/core.c index 35b79bee3a..80afacdae4 100644 --- a/package/mac80211/src/net/wireless/core.c +++ b/package/mac80211/src/net/wireless/core.c @@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_info *info) if (info->attrs[NL80211_ATTR_IFINDEX]) { ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev) { if (dev->ieee80211_ptr) byifidx = @@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifindex) struct net_device *dev; mutex_lock(&cfg80211_drv_mutex); - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (!dev) goto out; if (dev->ieee80211_ptr) { @@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) struct cfg80211_registered_device *drv; int alloc_size; + WARN_ON(!ops->add_key && ops->del_key); + WARN_ON(ops->add_key && !ops->del_key); + alloc_size = sizeof(*drv) + sizeof_priv; drv = kzalloc(alloc_size, GFP_KERNEL); @@ -229,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy) { struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); int res; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + bool have_band = false; + int i; + + /* sanity check supported bands/channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + sband->band = band; + + if (!sband->n_channels || !sband->n_bitrates) { + WARN_ON(1); + return -EINVAL; + } + + for (i = 0; i < sband->n_channels; i++) { + sband->channels[i].orig_flags = + sband->channels[i].flags; + sband->channels[i].orig_mag = + sband->channels[i].max_antenna_gain; + sband->channels[i].orig_mpwr = + sband->channels[i].max_power; + sband->channels[i].band = band; + } + + have_band = true; + } + + if (!have_band) { + WARN_ON(1); + return -EINVAL; + } + + /* check and set up bitrates */ + ieee80211_set_bitrate_flags(wiphy); + + /* set up regulatory info */ + wiphy_update_regulatory(wiphy); mutex_lock(&cfg80211_drv_mutex); diff --git a/package/mac80211/src/net/wireless/core.h b/package/mac80211/src/net/wireless/core.h index eb0f846b40..7a02c356d6 100644 --- a/package/mac80211/src/net/wireless/core.h +++ b/package/mac80211/src/net/wireless/core.h @@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, char *newname); +void ieee80211_set_bitrate_flags(struct wiphy *wiphy); +void wiphy_update_regulatory(struct wiphy *wiphy); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/package/mac80211/src/net/wireless/nl80211.c b/package/mac80211/src/net/wireless/nl80211.c index 58717f3037..5b3474798b 100644 --- a/package/mac80211/src/net/wireless/nl80211.c +++ b/package/mac80211/src/net/wireless/nl80211.c @@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info, return -EINVAL; ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); - *dev = dev_get_by_index(ifindex); + *dev = dev_get_by_index(&init_net, ifindex); if (!*dev) return -ENODEV; @@ -61,6 +61,28 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, + + [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, + + [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, + .len = WLAN_MAX_KEY_LEN }, + [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, + [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, + [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, + + [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, + [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, + [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, + [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, }; /* message building helper */ @@ -77,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { void *hdr; + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; + enum ieee80211_band band; + struct ieee80211_channel *chan; + struct ieee80211_rate *rate; + int i; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); if (!hdr) @@ -84,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); + if (!nl_bands) + goto nla_put_failure; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!dev->wiphy.bands[band]) + continue; + + nl_band = nla_nest_start(msg, band); + if (!nl_band) + goto nla_put_failure; + + /* add frequencies */ + nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); + if (!nl_freqs) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { + nl_freq = nla_nest_start(msg, i); + if (!nl_freq) + goto nla_put_failure; + + chan = &dev->wiphy.bands[band]->channels[i]; + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + nla_nest_end(msg, nl_freq); + } + + nla_nest_end(msg, nl_freqs); + + /* add bitrates */ + nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); + if (!nl_rates) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { + nl_rate = nla_nest_start(msg, i); + if (!nl_rate) + goto nla_put_failure; + + rate = &dev->wiphy.bands[band]->bitrates[i]; + NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, + rate->bitrate); + if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); + + nla_nest_end(msg, nl_rate); + } + + nla_nest_end(msg, nl_rates); + + nla_nest_end(msg, nl_band); + } + nla_nest_end(msg, nl_bands); + return genlmsg_end(msg, hdr); nla_put_failure: @@ -241,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } +static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { + [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, +}; + +static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) +{ + struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; + int flag; + + *mntrflags = 0; + + if (!nla) + return -EINVAL; + + if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, + nla, mntr_flags_policy)) + return -EINVAL; + + for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) + if (flags[flag]) + *mntrflags |= (1<<flag); + + return 0; +} + static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; int err, ifindex; enum nl80211_iftype type; struct net_device *dev; + u32 flags; if (info->attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); @@ -267,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); + err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, + type, err ? NULL : &flags); rtnl_unlock(); unlock: @@ -280,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 flags; if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -300,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, - nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags); rtnl_unlock(); unlock: @@ -335,6 +470,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) return err; } +struct get_key_cookie { + struct sk_buff *msg; + int error; +}; + +static void get_key_callback(void *c, struct key_params *params) +{ + struct get_key_cookie *cookie = c; + + if (params->key) + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, + params->key_len, params->key); + + if (params->seq) + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, + params->seq_len, params->seq); + + if (params->cipher) + NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, + params->cipher); + + return; + nla_put_failure: + cookie->error = 1; +} + +static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 key_idx = 0; + u8 *mac_addr = NULL; + struct get_key_cookie cookie = { + .error = 0, + }; + void *hdr; + struct sk_buff *msg; + + if (info->attrs[NL80211_ATTR_KEY_IDX]) + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + + if (key_idx > 3) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->get_key) { + err = -EOPNOTSUPP; + goto out; + } + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto out; + } + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_NEW_KEY); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto out; + } + + cookie.msg = msg; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); + if (mac_addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + rtnl_lock(); + err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, + &cookie, get_key_callback); + rtnl_unlock(); + + if (err) + goto out; + + if (cookie.error) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + err = genlmsg_unicast(msg, info->snd_pid); + goto out; + + nla_put_failure: + err = -ENOBUFS; + nlmsg_free(msg); + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 key_idx; + + if (!info->attrs[NL80211_ATTR_KEY_IDX]) + return -EINVAL; + + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + + if (key_idx > 3) + return -EINVAL; + + /* currently only support setting default key */ + if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) + return -EINVAL; + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->set_default_key) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct key_params params; + u8 key_idx = 0; + u8 *mac_addr = NULL; + + memset(¶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, @@ -374,6 +1158,73 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_GET_KEY, + .doit = nl80211_get_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_KEY, + .doit = nl80211_set_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_KEY, + .doit = nl80211_new_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_KEY, + .doit = nl80211_del_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_addset_beacon, + }, + { + .cmd = NL80211_CMD_NEW_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_addset_beacon, + }, + { + .cmd = NL80211_CMD_DEL_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_del_beacon, + }, + { + .cmd = NL80211_CMD_GET_STATION, + .doit = nl80211_get_station, + /* TODO: implement dumpit */ + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_STATION, + .doit = nl80211_set_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_STATION, + .doit = nl80211_new_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_STATION, + .doit = nl80211_del_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ diff --git a/package/mac80211/src/net/wireless/reg.c b/package/mac80211/src/net/wireless/reg.c new file mode 100644 index 0000000000..2b63c96dcf --- /dev/null +++ b/package/mac80211/src/net/wireless/reg.c @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This regulatory domain control implementation is highly incomplete, it + * only exists for the purpose of not regressing mac80211. + * + * For now, drivers can restrict the set of allowed channels by either + * not registering those channels or setting the IEEE80211_CHAN_DISABLED + * flag; that flag will only be *set* by this code, never *cleared. + * + * The usual implementation is for a driver to read a device EEPROM to + * determine which regulatory domain it should be operating under, then + * looking up the allowable channels in a driver-local table and finally + * registering those channels in the wiphy structure. + * + * Alternatively, drivers that trust the regulatory domain control here + * will register a complete set of capabilities and the control code + * will restrict the set by setting the IEEE80211_CHAN_* flags. + */ +#include <linux/kernel.h> +#include <net/wireless.h> +#include "core.h" + +static char *ieee80211_regdom = "US"; +module_param(ieee80211_regdom, charp, 0444); +MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); + +struct ieee80211_channel_range { + short start_freq; + short end_freq; + int max_power; + int max_antenna_gain; + u32 flags; +}; + +struct ieee80211_regdomain { + const char *code; + const struct ieee80211_channel_range *ranges; + int n_ranges; +}; + +#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \ + { _start, _end, _pwr, _ag, _flags } + + +/* + * Ideally, in the future, these definitions will be loaded from a + * userspace table via some daemon. + */ +static const struct ieee80211_channel_range ieee80211_US_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + /* IEEE 802.11a, channels 52..64 */ + RANGE_PWR(5260, 5320, 23, 6, 0), + /* IEEE 802.11a, channels 149..165, outdoor */ + RANGE_PWR(5745, 5825, 30, 6, 0), +}; + +static const struct ieee80211_channel_range ieee80211_JP_channels[] = { + /* IEEE 802.11b/g, channels 1..14 */ + RANGE_PWR(2412, 2484, 20, 6, 0), + /* IEEE 802.11a, channels 34..48 */ + RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN), + /* IEEE 802.11a, channels 52..64 */ + RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR), +}; + +#define REGDOM(_code) \ + { \ + .code = __stringify(_code), \ + .ranges = ieee80211_ ##_code## _channels, \ + .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \ + } + +static const struct ieee80211_regdomain ieee80211_regdoms[] = { + REGDOM(US), + REGDOM(JP), +}; + + +static const struct ieee80211_regdomain *get_regdom(void) +{ + static const struct ieee80211_channel_range + ieee80211_world_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + }; + static const struct ieee80211_regdomain regdom_world = REGDOM(world); + int i; + + for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++) + if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0) + return &ieee80211_regdoms[i]; + + return ®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); +} diff --git a/package/mac80211/src/net/wireless/sysfs.c b/package/mac80211/src/net/wireless/sysfs.c index 2d5d2255a2..29f820e182 100644 --- a/package/mac80211/src/net/wireless/sysfs.c +++ b/package/mac80211/src/net/wireless/sysfs.c @@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int wiphy_uevent(struct device *dev, char **envp, - int num_envp, char *buf, int size) +static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) { /* TODO, we probably need stuff here */ return 0; diff --git a/package/mac80211/src/net/wireless/util.c b/package/mac80211/src/net/wireless/util.c new file mode 100644 index 0000000000..77336c22fc --- /dev/null +++ b/package/mac80211/src/net/wireless/util.c @@ -0,0 +1,98 @@ +/* + * Wireless utility functions + * + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + */ +#include <net/wireless.h> +#include <asm/bitops.h> +#include "core.h" + +int ieee80211_channel_to_frequency(int chan) +{ + if (chan < 14) + return 2407 + chan * 5; + + if (chan == 14) + return 2484; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return (chan + 1000) * 5; +} +EXPORT_SYMBOL(ieee80211_channel_to_frequency); + +int ieee80211_frequency_to_channel(int freq) +{ + if (freq == 2484) + return 14; + + if (freq < 2484) + return (freq - 2407) / 5; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return freq/5 - 1000; +} +EXPORT_SYMBOL(ieee80211_frequency_to_channel); + +static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, + enum ieee80211_band band) +{ + int i, want; + + switch (band) { + case IEEE80211_BAND_5GHZ: + want = 3; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_A; + want--; + } + } + WARN_ON(want); + break; + case IEEE80211_BAND_2GHZ: + want = 7; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_B | + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate == 20 || + sband->bitrates[i].bitrate == 55 || + sband->bitrates[i].bitrate == 110 || + sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate != 10 && + sband->bitrates[i].bitrate != 20 && + sband->bitrates[i].bitrate != 55 && + sband->bitrates[i].bitrate != 110) + sband->bitrates[i].flags |= + IEEE80211_RATE_ERP_G; + } + WARN_ON(want != 0 && want != 3 && want != 6); + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } +} + +void ieee80211_set_bitrate_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + set_mandatory_flags_band(wiphy->bands[band], band); +} diff --git a/package/mac80211/src/net/wireless/wext.c b/package/mac80211/src/net/wireless/wext.c new file mode 100644 index 0000000000..a2d496f0b3 --- /dev/null +++ b/package/mac80211/src/net/wireless/wext.c @@ -0,0 +1,1522 @@ +/* + * This file implement the Wireless Extensions APIs. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +/************************** DOCUMENTATION **************************/ +/* + * API definition : + * -------------- + * See <linux/wireless.h> for details of the APIs and the rest. + * + * History : + * ------- + * + * v1 - 5.12.01 - Jean II + * o Created this file. + * + * v2 - 13.12.01 - Jean II + * o Move /proc/net/wireless stuff from net/core/dev.c to here + * o Make Wireless Extension IOCTLs go through here + * o Added iw_handler handling ;-) + * o Added standard ioctl description + * o Initial dumb commit strategy based on orinoco.c + * + * v3 - 19.12.01 - Jean II + * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call + * o Add event dispatcher function + * o Add event description + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * + * v4 - 18.04.02 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + * + * v5 - 21.06.02 - Jean II + * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) + * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + * o Add IWEVCUSTOM for driver specific event/scanning token + * o Turn on WE_STRICT_WRITE by default + kernel warning + * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) + * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + * + * v6 - 9.01.03 - Jean II + * o Add common spy support : iw_handler_set_spy(), wireless_spy_update() + * o Add enhanced spy support : iw_handler_set_thrspy() and event. + * o Add WIRELESS_EXT version display in /proc/net/wireless + * + * v6 - 18.06.04 - Jean II + * o Change get_spydata() method for added safety + * o Remove spy #ifdef, they are always on -> cleaner code + * o Allow any size GET request if user specifies length > max + * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV + * o Start migrating get_wireless_stats to struct iw_handler_def + * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus + * Based on patch from Pavel Roskin <proski@gnu.org> : + * o Fix kernel data leak to user space in private handler handling + * + * v7 - 18.3.05 - Jean II + * o Remove (struct iw_point *)->pointer from events and streams + * o Remove spy_offset from struct iw_handler_def + * o Start deprecating dev->get_wireless_stats, output a warning + * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless + * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) + * + * v8 - 17.02.06 - Jean II + * o RtNetlink requests support (SET/GET) + * + * v8b - 03.08.06 - Herbert Xu + * o Fix Wireless Event locking issues. + * + * v9 - 14.3.06 - Jean II + * o Change length in ESSID and NICK to strlen() instead of strlen()+1 + * o Make standard_ioctl_num and standard_event_num unsigned + * o Remove (struct net_device *)->get_wireless_stats() + * + * v10 - 16.3.07 - Jean II + * o Prevent leaking of kernel space in stream on 64 bits. + */ + +/***************************** INCLUDES *****************************/ + +#include <linux/module.h> +#include <linux/types.h> /* off_t */ +#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ +#include <linux/proc_fs.h> +#include <linux/rtnetlink.h> /* rtnetlink stuff */ +#include <linux/seq_file.h> +#include <linux/init.h> /* for __init */ +#include <linux/if_arp.h> /* ARPHRD_ETHER */ +#include <linux/etherdevice.h> /* compare_ether_addr */ +#include <linux/interrupt.h> +#include <net/net_namespace.h> + +#include <linux/wireless.h> /* Pretty obvious */ +#include <net/iw_handler.h> /* New driver API */ +#include <net/netlink.h> +#include <net/wext.h> + +#include <asm/uaccess.h> /* copy_to_user() */ + +/************************* GLOBAL VARIABLES *************************/ +/* + * You should not use global variables, because of re-entrancy. + * On our case, it's only const, so it's OK... + */ +/* + * Meta-data about all the standard Wireless Extension request we + * know about. + */ +static const struct iw_ioctl_description standard_ioctl[] = { + [SIOCSIWCOMMIT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWNAME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_CHAR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_range), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWPRIV - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_priv_args), + .max_tokens = 16, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSTATS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_statistics), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr), + .max_tokens = IW_MAX_SPY, + }, + [SIOCGIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_SPY, + }, + [SIOCSIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCGIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCSIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [SIOCGIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMLME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_mlme), + .max_tokens = sizeof(struct iw_mlme), + }, + [SIOCGIWAPLIST - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_AP, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = 0, + .max_tokens = sizeof(struct iw_scan_req), + }, + [SIOCGIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_SCAN_MAX_DATA, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCGIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCSIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCGIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCSIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCGIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCSIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCGIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCSIWPMKSA - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_pmksa), + .max_tokens = sizeof(struct iw_pmksa), + }, +}; +static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); + +/* + * Meta-data about all the additional standard Wireless Extension events + * we know about. + */ +static const struct iw_ioctl_description standard_event[] = { + [IWEVTXDROP - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVQUAL - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_QUAL, + }, + [IWEVCUSTOM - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_CUSTOM_MAX, + }, + [IWEVREGISTERED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVEXPIRED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVGENIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVMICHAELMICFAILURE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_michaelmicfailure), + }, + [IWEVASSOCREQIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVASSOCRESPIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVPMKIDCAND - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_pmkid_cand), + }, +}; +static const unsigned standard_event_num = ARRAY_SIZE(standard_event); + +/* Size (in bytes) of the various private data types */ +static const char iw_priv_type_size[] = { + 0, /* IW_PRIV_TYPE_NONE */ + 1, /* IW_PRIV_TYPE_BYTE */ + 1, /* IW_PRIV_TYPE_CHAR */ + 0, /* Not defined */ + sizeof(__u32), /* IW_PRIV_TYPE_INT */ + sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ + sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ + 0, /* Not defined */ +}; + +/* Size (in bytes) of various events */ +static const int event_type_size[] = { + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_POINT_LEN, /* Without variable payload */ + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; + + +/************************ COMMON SUBROUTINES ************************/ +/* + * Stuff that may be used in various place or doesn't fit in one + * of the section below. + */ + +/* ---------------------------------------------------------------- */ +/* + * Return the driver handler associated with a specific Wireless Extension. + */ +static iw_handler get_handler(struct net_device *dev, unsigned int cmd) +{ + /* Don't "optimise" the following variable, it will crash */ + unsigned int index; /* *MUST* be unsigned */ + + /* Check if we have some wireless handlers defined */ + if (dev->wireless_handlers == NULL) + return NULL; + + /* Try as a standard command */ + index = cmd - SIOCIWFIRST; + if (index < dev->wireless_handlers->num_standard) + return dev->wireless_handlers->standard[index]; + + /* Try as a private command */ + index = cmd - SIOCIWFIRSTPRIV; + if (index < dev->wireless_handlers->num_private) + return dev->wireless_handlers->private[index]; + + /* Not found */ + return NULL; +} + +/* ---------------------------------------------------------------- */ +/* + * Get statistics out of the driver + */ +static struct iw_statistics *get_wireless_stats(struct net_device *dev) +{ + /* New location */ + if ((dev->wireless_handlers != NULL) && + (dev->wireless_handlers->get_wireless_stats != NULL)) + return dev->wireless_handlers->get_wireless_stats(dev); + + /* Not found */ + return NULL; +} + +/* ---------------------------------------------------------------- */ +/* + * Call the commit handler in the driver + * (if exist and if conditions are right) + * + * Note : our current commit strategy is currently pretty dumb, + * but we will be able to improve on that... + * The goal is to try to agreagate as many changes as possible + * before doing the commit. Drivers that will define a commit handler + * are usually those that need a reset after changing parameters, so + * we want to minimise the number of reset. + * A cool idea is to use a timer : at each "set" command, we re-set the + * timer, when the timer eventually fires, we call the driver. + * Hopefully, more on that later. + * + * Also, I'm waiting to see how many people will complain about the + * netif_running(dev) test. I'm open on that one... + * Hopefully, the driver will remember to do a commit in "open()" ;-) + */ +static int call_commit_handler(struct net_device *dev) +{ + if ((netif_running(dev)) && + (dev->wireless_handlers->standard[0] != NULL)) + /* Call the commit handler on the driver */ + return dev->wireless_handlers->standard[0](dev, NULL, + NULL, NULL); + else + return 0; /* Command completed successfully */ +} + +/* ---------------------------------------------------------------- */ +/* + * Calculate size of private arguments + */ +static inline int get_priv_size(__u16 args) +{ + int num = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + return num * iw_priv_type_size[type]; +} + +/* ---------------------------------------------------------------- */ +/* + * Re-calculate the size of private arguments + */ +static inline int adjust_priv_size(__u16 args, + union iwreq_data * wrqu) +{ + int num = wrqu->data.length; + int max = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + /* Make sure the driver doesn't goof up */ + if (max < num) + num = max; + + return num * iw_priv_type_size[type]; +} + +/* ---------------------------------------------------------------- */ +/* + * Standard Wireless Handler : get wireless stats + * Allow programatic access to /proc/net/wireless even if /proc + * doesn't exist... Also more efficient... + */ +static int iw_handler_get_iwstats(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Get stats from the driver */ + struct iw_statistics *stats; + + stats = get_wireless_stats(dev); + if (stats) { + /* Copy statistics to extra */ + memcpy(extra, stats, sizeof(struct iw_statistics)); + wrqu->data.length = sizeof(struct iw_statistics); + + /* Check if we need to clear the updated flag */ + if (wrqu->data.flags != 0) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + return 0; + } else + return -EOPNOTSUPP; +} + +/* ---------------------------------------------------------------- */ +/* + * Standard Wireless Handler : get iwpriv definitions + * Export the driver private handler definition + * They will be picked up by tools like iwpriv... + */ +static int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Check if the driver has something to export */ + if ((dev->wireless_handlers->num_private_args == 0) || + (dev->wireless_handlers->private_args == NULL)) + return -EOPNOTSUPP; + + /* Check if there is enough buffer up there */ + if (wrqu->data.length < dev->wireless_handlers->num_private_args) { + /* User space can't know in advance how large the buffer + * needs to be. Give it a hint, so that we can support + * any size buffer we want somewhat efficiently... */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + return -E2BIG; + } + + /* Set the number of available ioctls. */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + + /* Copy structure to the user buffer. */ + memcpy(extra, dev->wireless_handlers->private_args, + sizeof(struct iw_priv_args) * wrqu->data.length); + + return 0; +} + + +/******************** /proc/net/wireless SUPPORT ********************/ +/* + * The /proc/net/wireless file is a human readable user-space interface + * exporting various wireless specific statistics from the wireless devices. + * This is the most popular part of the Wireless Extensions ;-) + * + * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). + * The content of the file is basically the content of "struct iw_statistics". + */ + +#ifdef CONFIG_PROC_FS + +/* ---------------------------------------------------------------- */ +/* + * Print one entry (line) of /proc/net/wireless + */ +static void wireless_seq_printf_stats(struct seq_file *seq, + struct net_device *dev) +{ + /* Get stats from the driver */ + struct iw_statistics *stats = get_wireless_stats(dev); + + if (stats) { + seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " + "%6d %6d %6d\n", + dev->name, stats->status, stats->qual.qual, + stats->qual.updated & IW_QUAL_QUAL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.level) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_LEVEL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.noise) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_NOISE_UPDATED + ? '.' : ' ', + stats->discard.nwid, stats->discard.code, + stats->discard.fragment, stats->discard.retries, + stats->discard.misc, stats->miss.beacon); + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + } +} + +/* ---------------------------------------------------------------- */ +/* + * Print info for /proc/net/wireless (print all entries) + */ +static int wireless_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "Inter-| sta-| Quality | Discarded " + "packets | Missed | WE\n" + " face | tus | link level noise | nwid " + "crypt frag retry misc | beacon | %d\n", + WIRELESS_EXT); + else + wireless_seq_printf_stats(seq, v); + return 0; +} + +static const struct seq_operations wireless_seq_ops = { + .start = dev_seq_start, + .next = dev_seq_next, + .stop = dev_seq_stop, + .show = wireless_seq_show, +}; + +static int wireless_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int res; + res = seq_open(file, &wireless_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_proc_net(inode); + if (!seq->private) { + seq_release(inode, file); + res = -ENXIO; + } + } + return res; +} + +static int wireless_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); +} + +static const struct file_operations wireless_seq_fops = { + .owner = THIS_MODULE, + .open = wireless_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = wireless_seq_release, +}; + +int wext_proc_init(struct net *net) +{ + /* Create /proc/net/wireless entry */ + if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) + return -ENOMEM; + + return 0; +} + +void wext_proc_exit(struct net *net) +{ + proc_net_remove(net, "wireless"); +} +#endif /* CONFIG_PROC_FS */ + +/************************** IOCTL SUPPORT **************************/ +/* + * The original user space API to configure all those Wireless Extensions + * is through IOCTLs. + * In there, we check if we need to call the new driver API (iw_handler) + * or just call the driver ioctl handler. + */ + +/* ---------------------------------------------------------------- */ +/* + * Wrapper to call a standard Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + */ +static int ioctl_standard_call(struct net_device * dev, + struct ifreq * ifr, + unsigned int cmd, + iw_handler handler) +{ + struct iwreq * iwr = (struct iwreq *) ifr; + const struct iw_ioctl_description * descr; + struct iw_request_info info; + int ret = -EINVAL; + + /* Get the description of the IOCTL */ + if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) + return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + /* Prepare the call */ + info.cmd = cmd; + info.flags = 0; + + /* Check if we have a pointer to user space data or not */ + if (descr->header_type != IW_HEADER_TYPE_POINT) { + + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), NULL); + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) + wireless_send_event(dev, cmd, &(iwr->u), NULL); + } else { + char * extra; + int extra_size; + int user_length = 0; + int err; + int essid_compat = 0; + + /* Calculate space needed by arguments. Always allocate + * for max space. Easier, and won't last long... */ + extra_size = descr->max_tokens * descr->token_size; + + /* Check need for ESSID compatibility for WE < 21 */ + switch (cmd) { + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + if (iwr->u.data.length == descr->max_tokens + 1) + essid_compat = 1; + else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { + char essid[IW_ESSID_MAX_SIZE + 1]; + + err = copy_from_user(essid, iwr->u.data.pointer, + iwr->u.data.length * + descr->token_size); + if (err) + return -EFAULT; + + if (essid[iwr->u.data.length - 1] == '\0') + essid_compat = 1; + } + break; + default: + break; + } + + iwr->u.data.length -= essid_compat; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if ((iwr->u.data.pointer == NULL) && + (iwr->u.data.length != 0)) + return -EFAULT; + /* Check if number of token fits within bounds */ + if (iwr->u.data.length > descr->max_tokens) + return -E2BIG; + if (iwr->u.data.length < descr->min_tokens) + return -EINVAL; + } else { + /* Check NULL pointer */ + if (iwr->u.data.pointer == NULL) + return -EFAULT; + /* Save user space buffer size for checking */ + user_length = iwr->u.data.length; + + /* Don't check if user_length > max to allow forward + * compatibility. The test user_length < min is + * implied by the test at the end. */ + + /* Support for very large requests */ + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && + (user_length > descr->max_tokens)) { + /* Allow userspace to GET more than max so + * we can support any size GET requests. + * There is still a limit : -ENOMEM. */ + extra_size = user_length * descr->token_size; + /* Note : user_length is originally a __u16, + * and token_size is controlled by us, + * so extra_size won't get negative and + * won't overflow... */ + } + } + + /* Create the kernel buffer */ + /* kzalloc ensures NULL-termination for essid_compat */ + extra = kzalloc(extra_size, GFP_KERNEL); + if (extra == NULL) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { + err = copy_from_user(extra, iwr->u.data.pointer, + iwr->u.data.length * + descr->token_size); + if (err) { + kfree(extra); + return -EFAULT; + } + } + + /* Call the handler */ + ret = handler(dev, &info, &(iwr->u), extra); + + iwr->u.data.length += essid_compat; + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { + /* Check if there is enough buffer up there */ + if (user_length < iwr->u.data.length) { + kfree(extra); + return -E2BIG; + } + + err = copy_to_user(iwr->u.data.pointer, extra, + iwr->u.data.length * + descr->token_size); + if (err) + ret = -EFAULT; + } + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) { + if (descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload */ + wireless_send_event(dev, cmd, &(iwr->u), NULL); + else + wireless_send_event(dev, cmd, &(iwr->u), + extra); + } + + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + /* Here, we will generate the appropriate event if needed */ + + return ret; +} + +/* ---------------------------------------------------------------- */ +/* + * Wrapper to call a private Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + * It's not as nice and slimline as the standard wrapper. The cause + * is struct iw_priv_args, which was not really designed for the + * job we are going here. + * + * IMPORTANT : This function prevent to set and get data on the same + * IOCTL and enforce the SET/GET convention. Not doing it would be + * far too hairy... + * If you need to set and get data at the same time, please don't use + * a iw_handler but process it in your ioctl handler (i.e. use the + * old driver API). + */ +static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, + unsigned int cmd, iw_handler handler) +{ + struct iwreq * iwr = (struct iwreq *) ifr; + const struct iw_priv_args * descr = NULL; + struct iw_request_info info; + int extra_size = 0; + int i; + int ret = -EINVAL; + + /* Get the description of the IOCTL */ + for (i = 0; i < dev->wireless_handlers->num_private_args; i++) + if (cmd == dev->wireless_handlers->private_args[i].cmd) { + descr = &(dev->wireless_handlers->private_args[i]); + break; + } + + /* Compute the size of the set/get arguments */ + if (descr != NULL) { + if (IW_IS_SET(cmd)) { + int offset = 0; /* For sub-ioctls */ + /* Check for sub-ioctl handler */ + if (descr->name[0] == '\0') + /* Reserve one int for sub-ioctl index */ + offset = sizeof(__u32); + + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if ((descr->set_args & IW_PRIV_SIZE_FIXED) && + ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of get arguments */ + extra_size = get_priv_size(descr->get_args); + + /* Does it fits in iwr ? */ + if ((descr->get_args & IW_PRIV_SIZE_FIXED) && + (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } + + /* Prepare the call */ + info.cmd = cmd; + info.flags = 0; + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); + } else { + char * extra; + int err; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if ((iwr->u.data.pointer == NULL) && + (iwr->u.data.length != 0)) + return -EFAULT; + + /* Does it fits within bounds ? */ + if (iwr->u.data.length > (descr->set_args & + IW_PRIV_SIZE_MASK)) + return -E2BIG; + } else if (iwr->u.data.pointer == NULL) + return -EFAULT; + + /* Always allocate for max space. Easier, and won't last + * long... */ + extra = kmalloc(extra_size, GFP_KERNEL); + if (extra == NULL) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { + err = copy_from_user(extra, iwr->u.data.pointer, + extra_size); + if (err) { + kfree(extra); + return -EFAULT; + } + } + + /* Call the handler */ + ret = handler(dev, &info, &(iwr->u), extra); + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { + + /* Adjust for the actual length if it's variable, + * avoid leaking kernel bits outside. */ + if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { + extra_size = adjust_priv_size(descr->get_args, + &(iwr->u)); + } + + err = copy_to_user(iwr->u.data.pointer, extra, + extra_size); + if (err) + ret = -EFAULT; + } + + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } + + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} + +/* ---------------------------------------------------------------- */ +/* + * Main IOCTl dispatcher. + * Check the type of IOCTL and call the appropriate wrapper... + */ +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) +{ + struct net_device *dev; + iw_handler handler; + + /* Permissions are already checked in dev_ioctl() before calling us. + * The copy_to/from_user() of ifr is also dealt with in there */ + + /* Make sure the device exist */ + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) + return -ENODEV; + + /* A bunch of special cases, then the generic case... + * Note that 'cmd' is already filtered in dev_ioctl() with + * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ + if (cmd == SIOCGIWSTATS) + return ioctl_standard_call(dev, ifr, cmd, + &iw_handler_get_iwstats); + + if (cmd == SIOCGIWPRIV && dev->wireless_handlers) + return ioctl_standard_call(dev, ifr, cmd, + &iw_handler_get_private); + + /* Basic check */ + if (!netif_device_present(dev)) + return -ENODEV; + + /* New driver API : try to find the handler */ + handler = get_handler(dev, cmd); + if (handler) { + /* Standard and private are not the same */ + if (cmd < SIOCIWFIRSTPRIV) + return ioctl_standard_call(dev, ifr, cmd, handler); + else + return ioctl_private_call(dev, ifr, cmd, handler); + } + /* Old driver API : call driver ioctl handler */ + if (dev->do_ioctl) + return dev->do_ioctl(dev, ifr, cmd); + return -EOPNOTSUPP; +} + +/* entry point from dev ioctl */ +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg) +{ + int ret; + + /* If command is `set a parameter', or + * `get the encoding parameters', check if + * the user has the right to do it */ + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) + && !capable(CAP_NET_ADMIN)) + return -EPERM; + + dev_load(net, ifr->ifr_name); + rtnl_lock(); + ret = wireless_process_ioctl(net, ifr, cmd); + rtnl_unlock(); + if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq))) + return -EFAULT; + return ret; +} + +/************************* EVENT PROCESSING *************************/ +/* + * Process events generated by the wireless layer or the driver. + * Most often, the event will be propagated through rtnetlink + */ + +/* ---------------------------------------------------------------- */ +/* + * Locking... + * ---------- + * + * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing + * the locking issue in here and implementing this code ! + * + * The issue : wireless_send_event() is often called in interrupt context, + * while the Netlink layer can never be called in interrupt context. + * The fully formed RtNetlink events are queued, and then a tasklet is run + * to feed those to Netlink. + * The skb_queue is interrupt safe, and its lock is not held while calling + * Netlink, so there is no possibility of dealock. + * Jean II + */ + +static struct sk_buff_head wireless_nlevent_queue; + +static int __init wireless_nlevent_init(void) +{ + skb_queue_head_init(&wireless_nlevent_queue); + return 0; +} + +subsys_initcall(wireless_nlevent_init); + +static void wireless_nlevent_process(unsigned long data) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&wireless_nlevent_queue))) + rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); +} + +static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); + +/* ---------------------------------------------------------------- */ +/* + * Fill a rtnetlink message with our event data. + * Note that we propage only the specified event and don't dump the + * current wireless config. Dumping the wireless config is far too + * expensive (for each parameter, the driver need to query the hardware). + */ +static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, + int type, char *event, int event_len) +{ + struct ifinfomsg *r; + struct nlmsghdr *nlh; + + nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); + if (nlh == NULL) + return -EMSGSIZE; + + r = nlmsg_data(nlh); + r->ifi_family = AF_UNSPEC; + r->__ifi_pad = 0; + r->ifi_type = dev->type; + r->ifi_index = dev->ifindex; + r->ifi_flags = dev_get_flags(dev); + r->ifi_change = 0; /* Wireless changes don't affect those flags */ + + /* Add the wireless events in the netlink packet */ + NLA_PUT(skb, IFLA_WIRELESS, event_len, event); + + return nlmsg_end(skb, nlh); + +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + +/* ---------------------------------------------------------------- */ +/* + * Create and broadcast and send it on the standard rtnetlink socket + * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c + * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field + * within a RTM_NEWLINK event. + */ +static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) +{ + struct sk_buff *skb; + int err; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; + + err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len); + if (err < 0) { + WARN_ON(err == -EMSGSIZE); + kfree_skb(skb); + return; + } + + NETLINK_CB(skb).dst_group = RTNLGRP_LINK; + skb_queue_tail(&wireless_nlevent_queue, skb); + tasklet_schedule(&wireless_nlevent_tasklet); +} + +/* ---------------------------------------------------------------- */ +/* + * Main event dispatcher. Called from other parts and drivers. + * Send the event on the appropriate channels. + * May be called from interrupt context. + */ +void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + char * extra) +{ + const struct iw_ioctl_description * descr = NULL; + int extra_len = 0; + struct iw_event *event; /* Mallocated whole event */ + int event_len; /* Its size */ + int hdr_len; /* Size of the event header */ + int wrqu_off = 0; /* Offset in wrqu */ + /* Don't "optimise" the following variable, it will crash */ + unsigned cmd_index; /* *MUST* be unsigned */ + + /* Get the description of the Event */ + if (cmd <= SIOCIWLAST) { + cmd_index = cmd - SIOCIWFIRST; + if (cmd_index < standard_ioctl_num) + descr = &(standard_ioctl[cmd_index]); + } else { + cmd_index = cmd - IWEVFIRST; + if (cmd_index < standard_event_num) + descr = &(standard_event[cmd_index]); + } + /* Don't accept unknown events */ + if (descr == NULL) { + /* Note : we don't return an error to the driver, because + * the driver would not know what to do about it. It can't + * return an error to the user, because the event is not + * initiated by a user request. + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ + printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } + + /* Check extra parameters and set extra_len */ + if (descr->header_type == IW_HEADER_TYPE_POINT) { + /* Check if number of token fits within bounds */ + if (wrqu->data.length > descr->max_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); + return; + } + if (wrqu->data.length < descr->min_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); + return; + } + /* Calculate extra_len - extra is NULL for restricted events */ + if (extra != NULL) + extra_len = wrqu->data.length * descr->token_size; + /* Always at an offset in wrqu */ + wrqu_off = IW_EV_POINT_OFF; + } + + /* Total length of the event */ + hdr_len = event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + + /* Create temporary buffer to hold the event */ + event = kmalloc(event_len, GFP_ATOMIC); + if (event == NULL) + return; + + /* Fill event */ + event->len = event_len; + event->cmd = cmd; + memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); + if (extra) + memcpy(((char *) event) + hdr_len, extra, extra_len); + + /* Send via the RtNetlink event channel */ + rtmsg_iwinfo(dev, (char *) event, event_len); + + /* Cleanup */ + kfree(event); + + return; /* Always success, I guess ;-) */ +} +EXPORT_SYMBOL(wireless_send_event); + +/********************** ENHANCED IWSPY SUPPORT **********************/ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to use those standard spy iw_handler in struct iw_handler_def, + * push data to us via wireless_spy_update() and include struct iw_spy_data + * in its private part (and export it in net_device->wireless_data->spy_data). + * One of the main advantage of centralising spy support here is that + * it becomes much easier to improve and extend it without having to touch + * the drivers. One example is the addition of the Spy-Threshold events. + */ + +/* ---------------------------------------------------------------- */ +/* + * Return the pointer to the spy data in the driver. + * Because this is called on the Rx path via wireless_spy_update(), + * we want it to be efficient... + */ +static inline struct iw_spy_data *get_spydata(struct net_device *dev) +{ + /* This is the new way */ + if (dev->wireless_data) + return dev->wireless_data->spy_data; + return NULL; +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set Spy List + */ +int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Disable spy collection while we copy the addresses. + * While we copy addresses, any call to wireless_spy_update() + * will NOP. This is OK, as anyway the addresses are changing. */ + spydata->spy_number = 0; + + /* We want to operate without locking, because wireless_spy_update() + * most likely will happen in the interrupt handler, and therefore + * have its own locking constraints and needs performance. + * The rtnl_lock() make sure we don't race with the other iw_handlers. + * This make sure wireless_spy_update() "see" that the spy list + * is temporarily disabled. */ + smp_wmb(); + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for (i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + } + + /* Make sure above is updated before re-enabling */ + smp_wmb(); + + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get Spy List + */ +int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for (i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if (spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for (i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; + return 0; +} +EXPORT_SYMBOL(iw_handler_get_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(spydata->spy_thr_low), &(threshold->low), + 2 * sizeof(struct iw_quality)); + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(threshold->low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_get_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); + /* Copy also thresholds */ + memcpy(&(threshold.low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ + struct iw_spy_data * spydata = get_spydata(dev); + int i; + int match = -1; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return; + + /* Update all records that match */ + for (i = 0; i < spydata->spy_number; i++) + if (!compare_ether_addr(address, spydata->spy_address[i])) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } + + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if (match >= 0) { + if (spydata->spy_thr_under[match]) { + if (wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if (wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +} +EXPORT_SYMBOL(wireless_spy_update); |