Upgrade b43 and mac80211.

This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211.
Will do that in a seperate patch.

SVN-Revision: 10466
lede-17.01
Michael Büsch 2008-02-15 22:47:47 +00:00
parent 4e45a1d1ac
commit 99aaf500ed
103 changed files with 17013 additions and 10185 deletions

View File

@ -23,11 +23,11 @@ PKG_FWV4_SOURCE_URL:=http://downloads.openwrt.org/sources/
PKG_FWV4_MD5SUM:=a7d8dde3ce474c361143b83e1d9890b1
PKG_FWCUTTER_NAME:=b43-fwcutter
PKG_FWCUTTER_VERSION=008
PKG_FWCUTTER_VERSION=011
PKG_FWCUTTER_SOURCE:=$(PKG_FWCUTTER_NAME)-$(PKG_FWCUTTER_VERSION).tar.bz2
PKG_FWCUTTER_SOURCE_URL:=http://download.berlios.de/bcm43xx/
PKG_FWCUTTER_MD5SUM:=3f7fbf4f8dcd296c6d1b0d42eab0f9ac
PKG_FWCUTTER_SOURCE_URL:=http://bu3sch.de/b43/fwcutter/
PKG_FWCUTTER_MD5SUM:=3db2f4de85a459451f5b391cf67a8d44
define KernelPackage/b43
SUBMENU:=Wireless Drivers
@ -43,7 +43,6 @@ endef
EXTRA_KCONFIG:= \
CONFIG_B43=m \
CONFIG_B43_DMA=y \
$(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \
@ -73,6 +72,8 @@ define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
tar xjf "$(DL_DIR)/$(PKG_FWV4_SOURCE)" -C "$(PKG_BUILD_DIR)"
tar xjf "$(DL_DIR)/$(PKG_FWCUTTER_SOURCE)" -C "$(PKG_BUILD_DIR)"
$(Build/Patch)
$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
endef
define Build/Configure

View File

@ -61,16 +61,28 @@ config B43_PCMCIA
If unsure, say N.
# LED support
config B43_NPHY
bool "Pre IEEE 802.11n support (BROKEN)"
depends on B43 && EXPERIMENTAL && BROKEN
---help---
Support for the IEEE 802.11n draft.
THIS IS BROKEN AND DOES NOT WORK YET.
SAY N.
# This config option automatically enables b43 LEDS support,
# if it's possible.
config B43_LEDS
bool
depends on B43 && MAC80211_LEDS
depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
default y
# RFKILL support
# This config option automatically enables b43 RFKILL support,
# if it's possible.
config B43_RFKILL
bool
depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
default y
config B43_DEBUG
@ -81,51 +93,3 @@ config B43_DEBUG
Say Y, if you want to find out why the driver does not
work for you.
config B43_DMA
bool
depends on B43
config B43_PIO
bool
depends on B43
choice
prompt "Broadcom 43xx data transfer mode"
depends on B43
default B43_DMA_AND_PIO_MODE
config B43_DMA_AND_PIO_MODE
bool "DMA + PIO"
select B43_DMA
select B43_PIO
---help---
Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
data transfer modes.
The actually used mode is selectable through the module
parameter "pio". If the module parameter is pio=0, DMA is used.
Otherwise PIO is used. DMA is default.
If unsure, choose this option.
config B43_DMA_MODE
bool "DMA (Direct Memory Access) only"
select B43_DMA
---help---
Only include Direct Memory Access (DMA).
This reduces the size of the driver module, by omitting the PIO code.
config B43_PIO_MODE
bool "PIO (Programmed I/O) only"
select B43_PIO
---help---
Only include Programmed I/O (PIO).
This reduces the size of the driver module, by omitting the DMA code.
Please note that PIO transfers are slow (compared to DMA).
Also note that not all devices of the 43xx series support PIO.
The 4306 (Apple Airport Extreme and others) supports PIO, while
the 4318 is known to _not_ support PIO.
Only use PIO, if DMA does not work for you.
endchoice

View File

@ -1,20 +1,16 @@
# b43 core
b43-y += main.o
b43-y += tables.o
b43-y += tables_nphy.o
b43-y += phy.o
b43-y += nphy.o
b43-y += sysfs.o
b43-y += xmit.o
b43-y += lo.o
# b43 RFKILL button support
b43-y += wa.o
b43-y += dma.o
b43-$(CONFIG_B43_RFKILL) += rfkill.o
# b43 LED support
b43-$(CONFIG_B43_LEDS) += leds.o
# b43 PCMCIA support
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
# b43 debugging
b43-$(CONFIG_B43_DEBUG) += debugfs.o
# b43 DMA and PIO
b43-$(CONFIG_B43_DMA) += dma.o
b43-$(CONFIG_B43_PIO) += pio.o
obj-$(CONFIG_B43) += b43.o

View File

@ -35,8 +35,8 @@
#define B43_MMIO_DMA4_IRQ_MASK 0x44
#define B43_MMIO_DMA5_REASON 0x48
#define B43_MMIO_DMA5_IRQ_MASK 0x4C
#define B43_MMIO_MACCTL 0x120
#define B43_MMIO_STATUS2_BITFIELD 0x124
#define B43_MMIO_MACCTL 0x120 /* MAC control */
#define B43_MMIO_MACCMD 0x124 /* MAC command */
#define B43_MMIO_GEN_IRQ_REASON 0x128
#define B43_MMIO_GEN_IRQ_MASK 0x12C
#define B43_MMIO_RAM_CONTROL 0x130
@ -50,6 +50,9 @@
#define B43_MMIO_XMITSTAT_1 0x174
#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
#define B43_MMIO_TSF_CFP_REP 0x188
#define B43_MMIO_TSF_CFP_START 0x18C
#define B43_MMIO_TSF_CFP_MAXDUR 0x190
/* 32-bit DMA */
#define B43_MMIO_DMA32_BASE0 0x200
@ -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;
};
/* 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);

View File

@ -34,7 +34,6 @@
#include "main.h"
#include "debugfs.h"
#include "dma.h"
#include "pio.h"
#include "xmit.h"
@ -128,7 +127,7 @@ static ssize_t shm_read_file(struct b43_wldev *dev,
__le16 *le16buf = (__le16 *)buf;
for (i = 0; i < 0x1000; i++) {
if (bufsize <= 0)
if (bufsize < sizeof(tmp))
break;
tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
le16buf[i] = cpu_to_le16(tmp);
@ -223,8 +222,6 @@ out:
static int txpower_g_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
unsigned long phy_flags;
if (dev->phy.type != B43_PHYTYPE_G)
return -ENODEV;
if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev,
dev->phy.tx_control |= B43_TXCTL_PA2DB;
if (pa3db)
dev->phy.tx_control |= B43_TXCTL_PA3DB;
b43_phy_lock(dev, phy_flags);
b43_phy_lock(dev);
b43_radio_lock(dev);
b43_set_txpower_g(dev, &dev->phy.bbatt,
&dev->phy.rfatt, dev->phy.tx_control);
b43_radio_unlock(dev);
b43_phy_unlock(dev, phy_flags);
b43_phy_unlock(dev);
}
return 0;
@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
struct b43_wldev *dev;
struct b43_debugfs_fops *dfops;
struct b43_dfs_file *dfile;
ssize_t ret;
ssize_t uninitialized_var(ret);
char *buf;
const size_t bufsize = 1024 * 128;
const size_t buforder = get_order(bufsize);

View File

@ -37,6 +37,8 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
/* 32bit DMA ops. */
static
@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
>> SSB_DMA_TRANSLATION_SHIFT;
addrhi |= ssb_dma_translation(ring->dev->dev);
addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
if (slot == ring->nr_slots - 1)
ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
if (start)
@ -315,29 +317,27 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
case 3:
ring = dev->dma.tx_ring0;
break;
case 4:
ring = dev->dma.tx_ring4;
break;
case 5:
ring = dev->dma.tx_ring5;
break;
}
return ring;
}
/* Bcm43xx-ring to mac80211-queue mapping */
/* b43-ring to mac80211-queue mapping */
static inline int txring_to_priority(struct b43_dmaring *ring)
{
static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
unsigned int index;
/*FIXME: have only one queue, for now */
return 0;
return idx_to_prio[ring->index];
index = ring->index;
if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
index = 0;
return idx_to_prio[index];
}
u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
{
static const u16 map64[] = {
B43_MMIO_DMA64_BASE0,
@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
B43_MMIO_DMA32_BASE5,
};
if (dma64bit) {
if (type == B43_DMA_64BIT) {
B43_WARN_ON(!(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map64)));
return map64[controller_idx];
@ -426,9 +426,21 @@ static inline
static int alloc_ringmemory(struct b43_dmaring *ring)
{
struct device *dev = ring->dev->dev->dev;
gfp_t flags = GFP_KERNEL;
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
* has shown that 4K is sufficient for the latter as long as the buffer
* does not cross an 8K boundary.
*
* For unknown reasons - possibly a hardware error - the BCM4311 rev
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
* which accounts for the GFP_DMA flag below.
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
&(ring->dmabase), GFP_KERNEL);
&(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
@ -447,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
}
/* Reset the RX DMA channel */
int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
enum b43_dmatype type)
{
int i;
u32 value;
@ -455,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
might_sleep();
offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
b43_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
B43_DMA32_RXSTATUS;
value = b43_read32(dev, mmio_base + offset);
if (dma64) {
if (type == B43_DMA_64BIT) {
value &= B43_DMA64_RXSTAT;
if (value == B43_DMA64_RXSTAT_DISABLED) {
i = -1;
@ -483,8 +497,9 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
return 0;
}
/* Reset the RX DMA channel */
int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
/* Reset the TX DMA channel */
static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
enum b43_dmatype type)
{
int i;
u32 value;
@ -493,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
might_sleep();
for (i = 0; i < 10; i++) {
offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
B43_DMA32_TXSTATUS;
value = b43_read32(dev, mmio_base + offset);
if (dma64) {
if (type == B43_DMA_64BIT) {
value &= B43_DMA64_TXSTAT;
if (value == B43_DMA64_TXSTAT_DISABLED ||
value == B43_DMA64_TXSTAT_IDLEWAIT ||
@ -510,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
}
msleep(1);
}
offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
b43_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
B43_DMA32_TXSTATUS;
value = b43_read32(dev, mmio_base + offset);
if (dma64) {
if (type == B43_DMA_64BIT) {
value &= B43_DMA64_TXSTAT;
if (value == B43_DMA64_TXSTAT_DISABLED) {
i = -1;
@ -540,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
return 0;
}
/* Check if a DMA mapping address is invalid. */
static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr,
size_t buffersize)
{
if (unlikely(dma_mapping_error(addr)))
return 1;
switch (ring->type) {
case B43_DMA_30BIT:
if ((u64)addr + buffersize > (1ULL << 30))
return 1;
break;
case B43_DMA_32BIT:
if ((u64)addr + buffersize > (1ULL << 32))
return 1;
break;
case B43_DMA_64BIT:
/* Currently we can't have addresses beyond
* 64bit in the kernel. */
break;
}
/* The address is OK. */
return 0;
}
static int setup_rx_descbuffer(struct b43_dmaring *ring,
struct b43_dmadesc_generic *desc,
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@ -555,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
if (unlikely(!skb))
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
if (dma_mapping_error(dmaaddr)) {
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
/* ugh. try to realloc in zone_dma */
gfp_flags |= GFP_DMA;
@ -568,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
ring->rx_buffersize, 0);
}
if (dma_mapping_error(dmaaddr)) {
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
dev_kfree_skb_any(skb);
return -EIO;
}
@ -633,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
u32 trans = ssb_dma_translation(ring->dev->dev);
if (ring->tx) {
if (ring->dma64) {
if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@ -647,7 +691,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
b43_dma_write(ring, B43_DMA64_TXRINGHI,
((ringbase >> 32) &
~SSB_DMA_TRANSLATION_MASK)
| trans);
| (trans << 1));
} else {
u32 ringbase = (u32) (ring->dmabase);
@ -665,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
err = alloc_initial_descbuffers(ring);
if (err)
goto out;
if (ring->dma64) {
if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@ -680,8 +724,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
b43_dma_write(ring, B43_DMA64_RXRINGHI,
((ringbase >> 32) &
~SSB_DMA_TRANSLATION_MASK)
| trans);
b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
| (trans << 1));
b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
sizeof(struct b43_dmadesc64));
} else {
u32 ringbase = (u32) (ring->dmabase);
@ -695,7 +740,8 @@ 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));
}
}
@ -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,6 +1232,12 @@ 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));
@ -1173,7 +1247,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
dev_kfree_skb_any(skb);
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;
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;
@ -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);

View File

@ -170,8 +170,6 @@ struct b43_dmadesc_generic {
#define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
#define B43_DMA3_RX_BUFFERSIZE 16
#ifdef CONFIG_B43_DMA
struct sk_buff;
struct b43_private;
struct b43_txstatus;
@ -205,6 +203,12 @@ struct b43_dma_ops {
void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
};
enum b43_dmatype {
B43_DMA_30BIT = 30,
B43_DMA_32BIT = 32,
B43_DMA_64BIT = 64,
};
struct b43_dmaring {
/* Lowlevel DMA ops. */
const struct b43_dma_ops *ops;
@ -237,8 +241,8 @@ struct b43_dmaring {
int index;
/* Boolean. Is this a TX ring? */
bool tx;
/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
bool dma64;
/* The type of DMA engine used. */
enum b43_dmatype type;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
/* Lock, only used for TX. */
@ -257,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
return b43_read32(ring->dev, ring->mmio_base + offset);
}
static inline
void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
{
b43_write32(ring->dev, ring->mmio_base + offset, value);
}
@ -266,13 +269,6 @@ static inline
int b43_dma_init(struct b43_wldev *dev);
void b43_dma_free(struct b43_wldev *dev);
int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64);
int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64);
u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
void b43_dma_tx_suspend(struct b43_wldev *dev);
void b43_dma_tx_resume(struct b43_wldev *dev);
@ -286,52 +282,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
void b43_dma_rx(struct b43_dmaring *ring);
#else /* CONFIG_B43_DMA */
static inline int b43_dma_init(struct b43_wldev *dev)
{
return 0;
}
static inline void b43_dma_free(struct b43_wldev *dev)
{
}
static inline
int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64)
{
return 0;
}
static inline
int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64)
{
return 0;
}
static inline
void b43_dma_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
return 0;
}
static inline
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
}
static inline void b43_dma_rx(struct b43_dmaring *ring)
{
}
static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
{
}
static inline void b43_dma_tx_resume(struct b43_wldev *dev)
{
}
#endif /* CONFIG_B43_DMA */
#endif /* B43_DMA_H_ */

View File

@ -4,7 +4,7 @@
LED control
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@ -163,6 +163,9 @@ static void b43_map_led(struct b43_wldev *dev,
b43_register_led(dev, &dev->led_radio, name,
b43_rfkill_led_name(dev),
led_index, activelow);
/* Sync the RF-kill LED state with the switch state. */
if (dev->radio_hw_enable)
b43_led_turn_on(dev, led_index, activelow);
break;
case B43_LED_WEIRD:
case B43_LED_ASSOC:
@ -187,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev)
enum b43_led_behaviour behaviour;
bool activelow;
sprom[0] = bus->sprom.r1.gpio0;
sprom[1] = bus->sprom.r1.gpio1;
sprom[2] = bus->sprom.r1.gpio2;
sprom[3] = bus->sprom.r1.gpio3;
sprom[0] = bus->sprom.gpio0;
sprom[1] = bus->sprom.gpio1;
sprom[2] = bus->sprom.gpio2;
sprom[3] = bus->sprom.gpio3;
for (i = 0; i < 4; i++) {
if (sprom[i] == 0xFF) {
@ -232,4 +235,5 @@ void b43_leds_exit(struct b43_wldev *dev)
b43_unregister_led(&dev->led_tx);
b43_unregister_led(&dev->led_rx);
b43_unregister_led(&dev->led_assoc);
b43_unregister_led(&dev->led_radio);
}

View File

@ -5,7 +5,7 @@
G PHY LO (LocalOscillator) Measuring and Control routines
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
rfover |= pga;
rfover |= lna;
rfover |= trsw_rx;
if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
phy->rev > 6)
if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
&& phy->rev > 6)
rfover |= B43_PHY_RFOVERVAL_EXTLNA;
b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
@ -555,20 +555,20 @@ struct lo_g_saved_values {
u16 phy_extg_01;
u16 phy_dacctl_hwpctl;
u16 phy_dacctl;
u16 phy_base_14;
u16 phy_cck_14;
u16 phy_hpwr_tssictl;
u16 phy_analogover;
u16 phy_analogoverval;
u16 phy_rfover;
u16 phy_rfoverval;
u16 phy_classctl;
u16 phy_base_3E;
u16 phy_cck_3E;
u16 phy_crs0;
u16 phy_pgactl;
u16 phy_base_2A;
u16 phy_cck_2A;
u16 phy_syncctl;
u16 phy_base_30;
u16 phy_base_06;
u16 phy_cck_30;
u16 phy_cck_06;
/* Radio registers */
u16 radio_43;
@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_DACCTL,
b43_phy_read(dev, B43_PHY_DACCTL)
| 0x40);
b43_phy_write(dev, B43_PHY_BASE(0x14),
b43_phy_read(dev, B43_PHY_BASE(0x14))
b43_phy_write(dev, B43_PHY_CCK(0x14),
b43_phy_read(dev, B43_PHY_CCK(0x14))
| 0x200);
}
if (phy->type == B43_PHYTYPE_B &&
phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
}
if (!lo->rebuild && b43_has_hardware_pctl(phy))
lo_read_power_vector(dev);
@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
b43_phy_write(dev, B43_PHY_CLASSCTL,
@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
& 0xFFFC);
if (phy->type == B43_PHYTYPE_G) {
if ((phy->rev >= 7) &&
(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
} else {
b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
} else {
b43_phy_write(dev, B43_PHY_RFOVER, 0);
}
b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
b43_phy_write(dev, B43_PHY_CCK(0x3E), 0);
}
sav->reg_3F4 = b43_read16(dev, 0x3F4);
sav->reg_3E2 = b43_read16(dev, 0x3E2);
sav->radio_43 = b43_radio_read16(dev, 0x43);
sav->radio_7A = b43_radio_read16(dev, 0x7A);
sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A));
sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
sav->radio_52 &= 0x00F0;
}
if (phy->type == B43_PHYTYPE_B) {
sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06));
b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF);
b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F);
} else {
b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
| 0x8000);
@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
& 0xF000);
tmp =
(phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
(phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E);
b43_phy_write(dev, tmp, 0x007F);
tmp = sav->phy_syncctl;
@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev,
tmp = sav->radio_7A;
b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3);
if (phy->type == B43_PHYTYPE_G ||
(phy->type == B43_PHYTYPE_B &&
phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003);
} else
b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
if (phy->rev >= 2)
b43_dummy_transmission(dev);
b43_radio_selectchannel(dev, 6, 0);
b43_radio_read16(dev, 0x51); /* dummy read */
if (phy->type == B43_PHYTYPE_G)
b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
if (lo->rebuild)
lo_measure_txctl_values(dev);
if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
} else {
if (phy->type == B43_PHYTYPE_B)
b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
else
b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
}
@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev,
}
if (phy->type == B43_PHYTYPE_G) {
if (phy->rev >= 3)
b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
else
b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
if (phy->rev >= 2)
b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202);
else
b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101);
}
b43_write16(dev, 0x3F4, sav->reg_3F4);
b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A);
b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
b43_radio_write16(dev, 0x43, sav->radio_43);
@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_write16(dev, 0x3E2, sav->reg_3E2);
if (phy->type == B43_PHYTYPE_B &&
phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30);
b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06);
}
if (phy->rev >= 2) {
b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
}
if (b43_has_hardware_pctl(phy)) {
@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
}
b43_radio_selectchannel(dev, sav->old_channel, 1);

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Stefano Brivio <stefano.brivio@polimi.it>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
@ -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);

489
package/b43/src/nphy.c Normal file
View File

@ -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;
}

932
package/b43/src/nphy.h Normal file
View File

@ -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_ */

View File

@ -65,12 +65,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
tuple_t tuple;
cisparse_t parse;
int err = -ENOMEM;
int res;
int res = 0;
unsigned char buf[64];
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
goto out;
goto out_error;
err = -ENODEV;
tuple.DesiredTuple = CISTPL_CONFIG;
@ -96,10 +96,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
dev->io.NumPorts2 = 0;
dev->io.Attributes2 = 0;
win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
WIN_ENABLE | WIN_DATA_WIDTH_16 |
WIN_USE_WAIT;
win.Base = 0;
win.Size = SSB_CORE_SIZE;
win.AccessSpeed = 1000;
win.AccessSpeed = 250;
res = pcmcia_request_window(&dev, &win, &dev->win);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
@ -108,21 +110,34 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
mem.Page = 0;
res = pcmcia_map_mem_page(dev->win, &mem);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
goto err_disable;
dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
dev->irq.Handler = NULL; /* The handler is registered later. */
dev->irq.Instance = NULL;
res = pcmcia_request_irq(dev, &dev->irq);
if (res != CS_SUCCESS)
goto err_disable;
res = pcmcia_request_configuration(dev, &dev->conf);
if (res != CS_SUCCESS)
goto err_disable;
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
if (err)
goto err_disable;
dev->priv = ssb;
out:
return err;
return 0;
err_disable:
pcmcia_disable_device(dev);
err_kfree_ssb:
kfree(ssb);
out_error:
printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
res, err);
return err;
}
@ -131,7 +146,6 @@ 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;
@ -144,7 +158,7 @@ static struct pcmcia_driver b43_pcmcia_driver = {
},
.id_table = b43_pcmcia_tbl,
.probe = b43_pcmcia_probe,
.remove = b43_pcmcia_remove,
.remove = __devexit_p(b43_pcmcia_remove),
.suspend = b43_pcmcia_suspend,
.resume = b43_pcmcia_resume,
};

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,21 @@ struct b43_phy;
/*** PHY Registers ***/
/* Routing */
#define B43_PHYROUTE_OFDM_GPHY 0x400
#define B43_PHYROUTE_EXT_GPHY 0x800
#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 */
/* Base registers. */
#define B43_PHY_BASE(reg) (reg)
/* OFDM (A) registers of a G-PHY */
/* 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);

View File

@ -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);
}

View File

@ -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_ */

View File

@ -25,6 +25,8 @@
#include "rfkill.h"
#include "b43.h"
#include <linux/kmod.h>
/* Returns TRUE, if the radio is enabled in hardware. */
static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
@ -47,32 +49,44 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
struct b43_wldev *dev = poll_dev->private;
struct b43_wl *wl = dev->wl;
bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex);
B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
mutex_unlock(&wl->mutex);
return;
}
enabled = b43_is_hw_radio_enabled(dev);
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
b43info(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED");
}
mutex_unlock(&wl->mutex);
input_report_key(poll_dev->input, KEY_WLAN, enabled);
} else
mutex_unlock(&wl->mutex);
/* 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);
snprintf(rfk->name, sizeof(rfk->name),
"b43-%s", wiphy_name(wl->hw->wiphy));
rfk->registered = 0;
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
if (!rfk->rfkill) {
b43warn(wl, "Failed to allocate RF-kill button\n");
return;
}
if (!rfk->rfkill)
goto out_error;
snprintf(rfk->name, sizeof(rfk->name),
"b43-%s", wiphy_name(wl->hw->wiphy));
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) {
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 */
} else
b43warn(wl, "Failed to allocate RF-kill polldev\n");
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;
}

View File

@ -15,14 +15,14 @@ struct b43_rfkill {
struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */
bool registered;
/* The unique name of this rfkill switch */
char name[32];
char name[sizeof("b43-phy4294967295")];
};
/* All the init functions return void, because we are not interested
/* The init function returns void, because we are not interested
* in failing the b43 init process when rfkill init failed. */
void b43_rfkill_alloc(struct b43_wldev *dev);
void b43_rfkill_free(struct b43_wldev *dev);
void b43_rfkill_init(struct b43_wldev *dev);
void b43_rfkill_exit(struct b43_wldev *dev);
@ -36,12 +36,6 @@ struct b43_rfkill {
/* empty */
};
static inline void b43_rfkill_alloc(struct b43_wldev *dev)
{
}
static inline void b43_rfkill_free(struct b43_wldev *dev)
{
}
static inline void b43_rfkill_init(struct b43_wldev *dev)
{
}

View File

@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count)
return ret;
}
static int get_boolean(const char *buf, size_t count)
{
if (count != 0) {
if (buf[0] == '1')
return 1;
if (buf[0] == '0')
return 0;
if (count >= 4 && memcmp(buf, "true", 4) == 0)
return 1;
if (count >= 5 && memcmp(buf, "false", 5) == 0)
return 0;
if (count >= 3 && memcmp(buf, "yes", 3) == 0)
return 1;
if (count >= 2 && memcmp(buf, "no", 2) == 0)
return 0;
if (count >= 2 && memcmp(buf, "on", 2) == 0)
return 1;
if (count >= 3 && memcmp(buf, "off", 3) == 0)
return 0;
}
return -EINVAL;
}
static ssize_t b43_attr_interfmode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
static DEVICE_ATTR(interference, 0644,
b43_attr_interfmode_show, b43_attr_interfmode_store);
static ssize_t b43_attr_preamble_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&wldev->wl->mutex);
if (wldev->short_preamble)
count =
snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
else
count =
snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
mutex_unlock(&wldev->wl->mutex);
return count;
}
static ssize_t b43_attr_preamble_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
unsigned long flags;
int value;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
value = get_boolean(buf, count);
if (value < 0)
return value;
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
wldev->short_preamble = !!value;
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return count;
}
static DEVICE_ATTR(shortpreamble, 0644,
b43_attr_preamble_show, b43_attr_preamble_store);
int b43_sysfs_register(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
int err;
B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
err = device_create_file(dev, &dev_attr_interference);
if (err)
goto out;
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
out:
return err;
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
goto out;
return device_create_file(dev, &dev_attr_interference);
}
void b43_sysfs_unregister(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
}

View File

@ -3,7 +3,7 @@
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = {
};
const u16 b43_tab_noisea3[] = {
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
0x5E5E, 0x5E5E, 0x5E5E, 0x3F48,
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
};
@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = {
0x0000, 0x0000, 0x0000, 0x0000,
};
const u16 b43_tab_noisescalea2[] = {
0x6767, 0x6767, 0x6767, 0x6767, /* 0 */
0x6767, 0x6767, 0x6767, 0x6767,
0x6767, 0x6767, 0x6767, 0x6767,
0x6767, 0x6700, 0x6767, 0x6767,
0x6767, 0x6767, 0x6767, 0x6767, /* 16 */
0x6767, 0x6767, 0x6767, 0x6767,
0x6767, 0x6767, 0x0067,
};
const u16 b43_tab_noisescalea3[] = {
0x2323, 0x2323, 0x2323, 0x2323, /* 0 */
0x2323, 0x2323, 0x2323, 0x2323,
0x2323, 0x2323, 0x2323, 0x2323,
0x2323, 0x2300, 0x2323, 0x2323,
0x2323, 0x2323, 0x2323, 0x2323, /* 16 */
0x2323, 0x2323, 0x2323, 0x2323,
0x2323, 0x2323, 0x0023,
};
const u16 b43_tab_noisescaleg1[] = {
0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
0x2F2D, 0x2A2A, 0x2527, 0x1F21,
@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = {
};
const u16 b43_tab_noisescaleg2[] = {
0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7, /* 0 */
0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
0x969B, 0x9195, 0x8F8F, 0x8A8A,
0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = {
0x00DE,
};
const u16 b43_tab_rssiagc1[] = {
0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */
0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE,
0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
};
const u16 b43_tab_rssiagc2[] = {
0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */
0x0820, 0x0820, 0x0820, 0x0820,
0x0820, 0x0820, 0x0920, 0x0A38,
0x0820, 0x0820, 0x0820, 0x0820,
0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */
0x0820, 0x0820, 0x0820, 0x0820,
0x0820, 0x0820, 0x0920, 0x0A38,
0x0820, 0x0820, 0x0820, 0x0820,
0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */
0x0820, 0x0820, 0x0820, 0x0820,
0x0820, 0x0820, 0x0920, 0x0A38,
0x0820, 0x0820, 0x0820, 0x0820,
};
static inline void assert_sizes(void)
{
BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
@ -317,36 +359,73 @@ static inline void assert_sizes(void)
BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
ARRAY_SIZE(b43_tab_noisescalea2));
BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
ARRAY_SIZE(b43_tab_noisescalea3));
BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg1));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg2));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg3));
BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1));
BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2));
}
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
{
assert_sizes();
struct b43_phy *phy = &dev->phy;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
return b43_phy_read(dev, B43_PHY_OTABLEI);
/* Some compiletime assertions... */
assert_sizes();
}
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value)
{
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
struct b43_phy *phy = &dev->phy;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
}
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
{
struct b43_phy *phy = &dev->phy;
u32 ret;
u16 addr;
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
ret <<= 16;
ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value)
{
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
struct b43_phy *phy = &dev->phy;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
}

View File

@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

674
package/b43/src/wa.c Normal file
View File

@ -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);
}

7
package/b43/src/wa.h Normal file
View File

@ -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_ */

View File

@ -5,7 +5,7 @@
Transmission (TX/RX) related functions.
Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@ -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,
/* 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),
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,9 +664,6 @@ 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);
}
@ -607,18 +693,12 @@ 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);
}
/* 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);
}

View File

@ -19,15 +19,15 @@ _b43_declare_plcp_hdr(6);
#undef _b43_declare_plcp_hdr
/* TX header for v4 firmware */
struct b43_txhdr_fw4 {
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 */
__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 */
@ -35,54 +35,146 @@ struct b43_txhdr_fw4 {
__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 */
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 */
struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP header */
__le16 dur_fb; /* Fallback duration */
__le16 mm_dur_time; /* Unused */
__le16 mm_dur_time_fb; /* Unused */
__le32 time_stamp; /* Timestamp */
__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 */
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 */
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 */
#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
void b43_generate_txhdr(struct b43_wldev *dev,
/* 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,
@ -170,7 +262,13 @@ struct b43_rxhdr_fw4 {
#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
/* MAC RX Status */
#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
#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 */
@ -180,11 +278,12 @@ struct b43_rxhdr_fw4 {
#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);

View File

@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
#CONFIG_DRIVER_PRISM54=y
# Driver interface for drivers using Devicescape IEEE 802.11 stack
CONFIG_DRIVER_DEVICESCAPE=y
#CONFIG_DRIVER_DEVICESCAPE=y
# Currently, driver_devicescape.c build requires some additional parameters
# to be able to include some of the kernel header files. Following lines can
# be used to set these (WIRELESS_DEV must point to the root directory of the

View File

@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
#CONFIG_DRIVER_PRISM54=y
# Driver interface for drivers using Devicescape IEEE 802.11 stack
CONFIG_DRIVER_DEVICESCAPE=y
#CONFIG_DRIVER_DEVICESCAPE=y
# Currently, driver_devicescape.c build requires some additional parameters
# to be able to include some of the kernel header files. Following lines can
# be used to set these (WIRELESS_DEV must point to the root directory of the

View File

@ -28,11 +28,12 @@ define KernelPackage/mac80211/description
Linux 802.11 Wireless Networking Stack
endef
CONFOPTS:=MAC80211 CFG80211 NL80211
CONFOPTS:=MAC80211 CFG80211 NL80211 MAC80211_RC_DEFAULT_PID MAC80211_RC_PID
BUILDFLAGS:= \
$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) -DCONFIG_MAC80211_RCSIMPLE=1) \
$(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS)
$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt)) \
$(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS) \
-D__CONFIG_MAC80211_RC_DEFAULT=pid
MAKE_OPTS:= \
CROSS_COMPILE="$(TARGET_CROSS)" \
@ -40,7 +41,7 @@ MAKE_OPTS:= \
EXTRA_CFLAGS="$(BUILDFLAGS)" \
$(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \
CONFIG_NL80211=y \
CONFIG_MAC80211_RCSIMPLE=y \
CONFIG_MAC80211_RC_PID=y \
CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \
LINUXINCLUDE="-I$(PKG_BUILD_DIR)/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,470 +0,0 @@
Subject: cfg80211/nl80211: introduce key handling
This introduces key handling to cfg80211/nl80211. Default
and group keys can be added, changed and removed; sequence
counters for each key can be retrieved.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 34 +++++
include/net/cfg80211.h | 44 +++++++
net/wireless/core.c | 3
net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 370 insertions(+)
--- everything.orig/include/linux/nl80211.h 2007-10-30 15:33:43.587381346 +0100
+++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100
@@ -37,6 +37,16 @@
* userspace to request deletion of a virtual interface, then requires
* attribute %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
+ * %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ * attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -54,6 +64,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_INTERFACE,
NL80211_CMD_DEL_INTERFACE,
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -75,6 +90,17 @@ enum nl80211_commands {
* @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
*
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -89,6 +115,14 @@ enum nl80211_attrs {
NL80211_ATTR_IFNAME,
NL80211_ATTR_IFTYPE,
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- everything.orig/net/wireless/nl80211.c 2007-10-30 15:33:43.637380153 +0100
+++ everything/net/wireless/nl80211.c 2007-11-07 13:19:38.201511066 +0100
@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+
+ [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+
+ [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
+ .len = WLAN_MAX_KEY_LEN },
+ [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
+ [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+ [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
};
/* message building helper */
@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct
return err;
}
+struct get_key_cookie {
+ struct sk_buff *msg;
+ int error;
+};
+
+static void get_key_callback(void *c, struct key_params *params)
+{
+ struct get_key_cookie *cookie = c;
+
+ if (params->key)
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
+ params->key_len, params->key);
+
+ if (params->seq)
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
+ params->seq_len, params->seq);
+
+ if (params->cipher)
+ NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
+ params->cipher);
+
+ return;
+ nla_put_failure:
+ cookie->error = 1;
+}
+
+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+ struct get_key_cookie cookie = {
+ .error = 0,
+ };
+ void *hdr;
+ struct sk_buff *msg;
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->get_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_NEW_KEY);
+
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto out;
+ }
+
+ cookie.msg = msg;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ if (mac_addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+ rtnl_lock();
+ err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+ &cookie, get_key_callback);
+ rtnl_unlock();
+
+ if (err)
+ goto out;
+
+ if (cookie.error)
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+ nla_put_failure:
+ err = -ENOBUFS;
+ nlmsg_free(msg);
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx;
+
+ if (!info->attrs[NL80211_ATTR_KEY_IDX])
+ return -EINVAL;
+
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ /* currently only support setting default key */
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->set_default_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct key_params params;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+ params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+ params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+ }
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ /*
+ * Disallow pairwise keys with non-zero index unless it's WEP
+ * (because current deployments use pairwise WEP keys with
+ * non-zero indizes but 802.11i clearly specifies to use zero)
+ */
+ if (mac_addr && key_idx &&
+ params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ params.cipher != WLAN_CIPHER_SUITE_WEP104)
+ return -EINVAL;
+
+ /* TODO: add definitions for the lengths to linux/ieee80211.h */
+ switch (params.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ if (params.key_len != 5)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params.key_len != 32)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params.key_len != 16)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (params.key_len != 13)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->add_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 key_idx = 0;
+ u8 *mac_addr = NULL;
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (key_idx > 3)
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_GET_KEY,
+ .doit = nl80211_get_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_KEY,
+ .doit = nl80211_set_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_KEY,
+ .doit = nl80211_new_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_KEY,
+ .doit = nl80211_del_key,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
--- everything.orig/net/wireless/core.c 2007-10-30 15:33:43.677380478 +0100
+++ everything/net/wireless/core.c 2007-11-07 13:19:38.221513833 +0100
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
struct cfg80211_registered_device *drv;
int alloc_size;
+ WARN_ON(!ops->add_key && ops->del_key);
+ WARN_ON(ops->add_key && !ops->del_key);
+
alloc_size = sizeof(*drv) + sizeof_priv;
drv = kzalloc(alloc_size, GFP_KERNEL);
--- everything.orig/include/net/cfg80211.h 2007-10-30 15:33:43.617381780 +0100
+++ everything/include/net/cfg80211.h 2007-11-07 13:19:38.231512748 +0100
@@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
struct ieee80211_radiotap_iterator *iterator);
+ /**
+ * struct key_params - key information
+ *
+ * Information about a key
+ *
+ * @key: key material
+ * @key_len: length of key material
+ * @cipher: cipher suite selector
+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
+ * with the get_key() callback, must be in little endian,
+ * length given by @seq_len.
+ */
+struct key_params {
+ u8 *key;
+ u8 *seq;
+ int key_len;
+ int seq_len;
+ u32 cipher;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -71,6 +91,18 @@ struct wiphy;
*
* @change_virtual_intf: change type of virtual interface
*
+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
+ * when adding a group key.
+ *
+ * @get_key: get information about the key with the given parameters.
+ * @mac_addr will be %NULL when requesting information for a group
+ * key. All pointers given to the @callback function need not be valid
+ * after it returns.
+ *
+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
+ * and @key_index
+ *
+ * @set_default_key: set the default key on an interface
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -78,6 +110,18 @@ struct cfg80211_ops {
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type);
+
+ int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr,
+ struct key_params *params);
+ int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params*));
+ int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, u8 *mac_addr);
+ int (*set_default_key)(struct wiphy *wiphy,
+ struct net_device *netdev,
+ u8 key_index);
};
#endif /* __NET_CFG80211_H */

View File

@ -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,
};

View File

@ -1,161 +0,0 @@
Subject: mac80211: support getting key sequence counters via cfg80211
This implements cfg80211's get_key() to allow retrieving the sequence
counter for a TKIP or CCMP key from userspace. It also cleans up and
documents the associated low-level driver interface.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/mac80211.h | 14 ++------
net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 89 insertions(+), 10 deletions(-)
Index: mac80211/net/mac80211/cfg.c
===================================================================
--- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:46:41.497954646 +0100
+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:46:51.346515884 +0100
@@ -1,7 +1,7 @@
/*
* mac80211 configuration hooks for cfg80211
*
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*
* This file is GPLv2 as found in COPYING.
*/
@@ -180,6 +180,88 @@
return 0;
}
+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params *params))
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta = NULL;
+ u8 seq[6] = {0};
+ struct key_params params;
+ struct ieee80211_key *key;
+ u32 iv32;
+ u16 iv16;
+ int err = -ENOENT;
+
+ if (mac_addr) {
+ sta = sta_info_get(sdata->local, mac_addr);
+ if (!sta)
+ goto out;
+
+ key = sta->key;
+ } else
+ key = sdata->keys[key_idx];
+
+ if (!key)
+ goto out;
+
+ memset(&params, 0, sizeof(params));
+
+ switch (key->conf.alg) {
+ case ALG_TKIP:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+
+ iv32 = key->u.tkip.iv32;
+ iv16 = key->u.tkip.iv16;
+
+ if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+ sdata->local->ops->get_tkip_seq)
+ sdata->local->ops->get_tkip_seq(
+ local_to_hw(sdata->local),
+ key->conf.hw_key_idx,
+ &iv32, &iv16);
+
+ seq[0] = iv16 & 0xff;
+ seq[1] = (iv16 >> 8) & 0xff;
+ seq[2] = iv32 & 0xff;
+ seq[3] = (iv32 >> 8) & 0xff;
+ seq[4] = (iv32 >> 16) & 0xff;
+ seq[5] = (iv32 >> 24) & 0xff;
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
+ case ALG_CCMP:
+ params.cipher = WLAN_CIPHER_SUITE_CCMP;
+ seq[0] = key->u.ccmp.tx_pn[5];
+ seq[1] = key->u.ccmp.tx_pn[4];
+ seq[2] = key->u.ccmp.tx_pn[3];
+ seq[3] = key->u.ccmp.tx_pn[2];
+ seq[4] = key->u.ccmp.tx_pn[1];
+ seq[5] = key->u.ccmp.tx_pn[0];
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
+ case ALG_WEP:
+ if (key->conf.keylen == 5)
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ }
+
+ params.key = key->conf.key;
+ params.key_len = key->conf.keylen;
+
+ callback(cookie, &params);
+ err = 0;
+
+ out:
+ if (sta)
+ sta_info_put(sta);
+ return err;
+}
+
static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
@@ -198,5 +280,6 @@
.change_virtual_intf = ieee80211_change_iface,
.add_key = ieee80211_add_key,
.del_key = ieee80211_del_key,
+ .get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
};
Index: mac80211/include/net/mac80211.h
===================================================================
--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:46:41.377947807 +0100
+++ mac80211/include/net/mac80211.h 2007-11-11 15:47:08.183475366 +0100
@@ -598,9 +598,6 @@
u8 key[0];
};
-#define IEEE80211_SEQ_COUNTER_RX 0
-#define IEEE80211_SEQ_COUNTER_TX 1
-
/**
* enum set_key_cmd - key command
*
@@ -947,9 +944,9 @@
*
* @get_stats: return low-level statistics
*
- * @get_sequence_counter: For devices that have internal sequence counters this
- * callback allows mac80211 to access the current value of a counter.
- * This callback seems not well-defined, tell us if you need it.
+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
+ * callback should be provided to read the TKIP transmit IVs (both IV32
+ * and IV16) for the given key from hardware.
*
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
*
@@ -1022,9 +1019,8 @@
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
- int (*get_sequence_counter)(struct ieee80211_hw *hw,
- u8* addr, u8 keyidx, u8 txrx,
- u32* iv32, u16* iv16);
+ void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
+ u32 *iv32, u16 *iv16);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_retry_limit)(struct ieee80211_hw *hw,

View File

@ -1,279 +0,0 @@
Subject: cfg80211/nl80211: add beacon settings
This adds the necessary API to cfg80211/nl80211 to allow
changing beaconing settings.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 24 ++++++++
include/net/cfg80211.h | 33 +++++++++++
net/wireless/nl80211.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 190 insertions(+)
--- everything.orig/include/net/cfg80211.h 2007-11-08 11:50:57.412840007 +0100
+++ everything/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
@@ -69,6 +69,26 @@ struct key_params {
u32 cipher;
};
+/**
+ * struct beacon_parameters - beacon parameters
+ *
+ * Used to configure the beacon for an interface.
+ *
+ * @head: head portion of beacon (before TIM IE)
+ * or %NULL if not changed
+ * @tail: tail portion of beacon (after TIM IE)
+ * or %NULL if not changed
+ * @interval: beacon interval or zero if not changed
+ * @dtim_period: DTIM period or zero if not changed
+ * @head_len: length of @head
+ * @tail_len: length of @tail
+ */
+struct beacon_parameters {
+ u8 *head, *tail;
+ int interval, dtim_period;
+ int head_len, tail_len;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -103,6 +123,13 @@ struct wiphy;
* and @key_index
*
* @set_default_key: set the default key on an interface
+ *
+ * @add_beacon: Add a beacon with given parameters, @head, @interval
+ * and @dtim_period will be valid, @tail is optional.
+ * @set_beacon: Change the beacon parameters for an access point mode
+ * interface. This should reject the call when no beacon has been
+ * configured.
+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -122,6 +149,12 @@ struct cfg80211_ops {
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
+
+ int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/include/linux/nl80211.h 2007-11-08 11:50:57.362839952 +0100
+++ everything/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
@@ -47,6 +47,15 @@
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
* or %NL80211_ATTR_MAC.
*
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -69,6 +78,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_KEY,
NL80211_CMD_DEL_KEY,
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -101,6 +115,11 @@ enum nl80211_commands {
* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
* CCMP keys, each six bytes in little endian
*
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -123,6 +142,11 @@ enum nl80211_attrs {
NL80211_ATTR_KEY_SEQ,
NL80211_ATTR_KEY_DEFAULT,
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- everything.orig/net/wireless/nl80211.c 2007-11-08 11:50:57.382836589 +0100
+++ everything/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
+
+ [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
+ [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* message building helper */
@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf
return err;
}
+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+ int (*call)(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info);
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct beacon_parameters params;
+ int haveinfo = 0;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ switch (info->genlhdr->cmd) {
+ case NL80211_CMD_NEW_BEACON:
+ /* these are required for NEW_BEACON */
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ call = drv->ops->add_beacon;
+ break;
+ case NL80211_CMD_SET_BEACON:
+ call = drv->ops->set_beacon;
+ break;
+ default:
+ WARN_ON(1);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!call) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ memset(&params, 0, sizeof(params));
+
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ params.interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+ params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ params.head_len =
+ nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ haveinfo = 1;
+ }
+
+ if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
+ params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ params.tail_len =
+ nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ haveinfo = 1;
+ }
+
+ if (!haveinfo) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = call(&drv->wiphy, dev, &params);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_beacon) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_beacon(&drv->wiphy, dev);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_SET_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_addset_beacon,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_addset_beacon,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_BEACON,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .doit = nl80211_del_beacon,
+ },
};
/* multicast groups */

View File

@ -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));

View File

@ -1,464 +0,0 @@
Subject: cfg80211/nl80211: station handling
This patch adds station handling to cfg80211/nl80211.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/nl80211.h | 68 +++++++++++++
include/net/cfg80211.h | 54 ++++++++++
net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 358 insertions(+)
--- everything.orig/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
+++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100
@@ -7,6 +7,18 @@
*/
/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -56,6 +68,16 @@
* parameters are like for %NL80211_CMD_SET_BEACON.
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
*
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -83,6 +105,11 @@ enum nl80211_commands {
NL80211_CMD_NEW_BEACON,
NL80211_CMD_DEL_BEACON,
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
/* add commands here */
/* used to define NL80211_CMD_MAX below */
@@ -120,6 +147,17 @@ enum nl80211_commands {
* @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
* @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
*
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags.
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -147,12 +185,20 @@ enum nl80211_attrs {
NL80211_ATTR_BEACON_HEAD,
NL80211_ATTR_BEACON_TAIL,
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
+#define NL80211_MAX_SUPP_RATES 32
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -184,4 +230,26 @@ enum nl80211_iftype {
NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
};
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
--- everything.orig/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
+++ everything/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100
@@ -89,6 +89,47 @@ struct beacon_parameters {
int head_len, tail_len;
};
+/**
+ * enum station_flags - station flags
+ *
+ * Station capability flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @STATION_FLAG_CHANGED: station flags were changed
+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short preambles
+ * @STATION_FLAG_WME: station is WME/QoS capable
+ */
+enum station_flags {
+ STATION_FLAG_CHANGED = 1<<0,
+ STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
+ STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
+ STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
+};
+
+/**
+ * struct station_parameters - station parameters
+ *
+ * Used to change and create a new station.
+ *
+ * @vlan: vlan interface station should belong to
+ * @supported_rates: supported rates in IEEE 802.11 format
+ * (or NULL for no change)
+ * @supported_rates_len: number of supported rates
+ * @station_flags: station flags (see &enum station_flags)
+ * @listen_interval: listen interval or -1 for no change
+ * @aid: AID or zero for no change
+ */
+struct station_parameters {
+ u8 *supported_rates;
+ struct net_device *vlan;
+ u32 station_flags;
+ int listen_interval;
+ u16 aid;
+ u8 supported_rates_len;
+};
+
/* from net/wireless.h */
struct wiphy;
@@ -130,6 +171,12 @@ struct wiphy;
* interface. This should reject the call when no beacon has been
* configured.
* @del_beacon: Remove beacon configuration and stop sending the beacon.
+ *
+ * @add_station: Add a new station.
+ *
+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ *
+ * @change_station: Modify a given station.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -155,6 +202,13 @@ struct cfg80211_ops {
int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+
+ int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params);
+ int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac);
+ int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
+++ everything/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100
@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
+ [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_RATES },
+ [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
};
/* message building helper */
@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
return err;
}
+static
+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
+ [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+};
+
+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+{
+ struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+ int flag;
+
+ *staflags = 0;
+
+ if (!nla)
+ return 0;
+
+ if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
+ nla, sta_flags_policy))
+ return -EINVAL;
+
+ *staflags = STATION_FLAG_CHANGED;
+
+ for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
+ if (flags[flag])
+ *staflags |= (1<<flag);
+
+ return 0;
+}
+
+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+/*
+ * Get vlan interface making sure it is on the right wiphy.
+ */
+static int get_vlan(struct nlattr *vlanattr,
+ struct cfg80211_registered_device *rdev,
+ struct net_device **vlan)
+{
+ *vlan = NULL;
+
+ if (vlanattr) {
+ *vlan = dev_get_by_index(nla_get_u32(vlanattr));
+ if (!*vlan)
+ return -ENODEV;
+ if (!(*vlan)->ieee80211_ptr)
+ return -EINVAL;
+ if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct station_parameters params;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ params.listen_interval = -1;
+
+ if (info->attrs[NL80211_ATTR_STA_AID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
+ params.supported_rates =
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.supported_rates_len =
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ }
+
+ if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+ params.listen_interval =
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+ &params.station_flags))
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ if (err)
+ goto out;
+
+ if (!drv->ops->change_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ if (params.vlan)
+ dev_put(params.vlan);
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct station_parameters params;
+ u8 *mac_addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_AID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ params.supported_rates =
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.supported_rates_len =
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.listen_interval =
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+ params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+ &params.station_flags))
+ return -EINVAL;
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ if (err)
+ goto out;
+
+ if (!drv->ops->add_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+ rtnl_unlock();
+
+ out:
+ if (params.vlan)
+ dev_put(params.vlan);
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *mac_addr = NULL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_station) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM,
.doit = nl80211_del_beacon,
},
+ {
+ .cmd = NL80211_CMD_GET_STATION,
+ .doit = nl80211_get_station,
+ /* TODO: implement dumpit */
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_STATION,
+ .doit = nl80211_set_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_STATION,
+ .doit = nl80211_new_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_STATION,
+ .doit = nl80211_del_station,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */

View File

@ -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,
};

View File

@ -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;
}
/*

View File

@ -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,
};

View File

@ -54,6 +54,8 @@
#define IEEE80211_STYPE_ACTION 0x00D0
/* control */
#define IEEE80211_STYPE_BACK_REQ 0x0080
#define IEEE80211_STYPE_BACK 0x0090
#define IEEE80211_STYPE_PSPOLL 0x00A0
#define IEEE80211_STYPE_RTS 0x00B0
#define IEEE80211_STYPE_CTS 0x00C0
@ -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

View File

@ -6,6 +6,18 @@
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/
/**
* DOC: Station handling
*
* Stations are added per interface, but a special case exists with VLAN
* interfaces. When a station is bound to an AP interface, it may be moved
* into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
* The station is still assumed to belong to the AP interface it was added
* to.
*
* TODO: need more info?
*/
/**
* enum nl80211_commands - supported nl80211 commands
*
@ -25,7 +37,7 @@
* either a dump request on a %NL80211_ATTR_WIPHY or a specific get
* on an %NL80211_ATTR_IFINDEX is supported.
* @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
* to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
@ -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 */

View File

@ -49,6 +49,140 @@ extern int ieee80211_radiotap_iterator_next(
struct ieee80211_radiotap_iterator *iterator);
/**
* struct key_params - key information
*
* Information about a key
*
* @key: key material
* @key_len: length of key material
* @cipher: cipher suite selector
* @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
* with the get_key() callback, must be in little endian,
* length given by @seq_len.
*/
struct key_params {
u8 *key;
u8 *seq;
int key_len;
int seq_len;
u32 cipher;
};
/**
* struct beacon_parameters - beacon parameters
*
* Used to configure the beacon for an interface.
*
* @head: head portion of beacon (before TIM IE)
* or %NULL if not changed
* @tail: tail portion of beacon (after TIM IE)
* or %NULL if not changed
* @interval: beacon interval or zero if not changed
* @dtim_period: DTIM period or zero if not changed
* @head_len: length of @head
* @tail_len: length of @tail
*/
struct beacon_parameters {
u8 *head, *tail;
int interval, dtim_period;
int head_len, tail_len;
};
/**
* enum station_flags - station flags
*
* Station capability flags. Note that these must be the bits
* according to the nl80211 flags.
*
* @STATION_FLAG_CHANGED: station flags were changed
* @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
* @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
* with short preambles
* @STATION_FLAG_WME: station is WME/QoS capable
*/
enum station_flags {
STATION_FLAG_CHANGED = 1<<0,
STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
};
/**
* struct station_parameters - station parameters
*
* Used to change and create a new station.
*
* @vlan: vlan interface station should belong to
* @supported_rates: supported rates in IEEE 802.11 format
* (or NULL for no change)
* @supported_rates_len: number of supported rates
* @station_flags: station flags (see &enum station_flags)
* @listen_interval: listen interval or -1 for no change
* @aid: AID or zero for no change
*/
struct station_parameters {
u8 *supported_rates;
struct net_device *vlan;
u32 station_flags;
int listen_interval;
u16 aid;
u8 supported_rates_len;
};
/**
* enum station_stats_flags - station statistics flags
*
* Used by the driver to indicate which info in &struct station_stats
* it has filled in during get_station().
*
* @STATION_STAT_INACTIVE_TIME: @inactive_time filled
* @STATION_STAT_RX_BYTES: @rx_bytes filled
* @STATION_STAT_TX_BYTES: @tx_bytes filled
*/
enum station_stats_flags {
STATION_STAT_INACTIVE_TIME = 1<<0,
STATION_STAT_RX_BYTES = 1<<1,
STATION_STAT_TX_BYTES = 1<<2,
};
/**
* struct station_stats - station statistics
*
* Station information filled by driver for get_station().
*
* @filled: bitflag of flags from &enum station_stats_flags
* @inactive_time: time since last station activity (tx/rx) in milliseconds
* @rx_bytes: bytes received from this station
* @tx_bytes: bytes transmitted to this station
*/
struct station_stats {
u32 filled;
u32 inactive_time;
u32 rx_bytes;
u32 tx_bytes;
};
/**
* enum monitor_flags - monitor flags
*
* Monitor interface configuration flags. Note that these must be the bits
* according to the nl80211 flags.
*
* @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
* @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
* @MONITOR_FLAG_CONTROL: pass control frames
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing
*/
enum monitor_flags {
MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL,
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
};
/* from net/wireless.h */
struct wiphy;
@ -71,13 +205,66 @@ struct wiphy;
*
* @change_virtual_intf: change type of virtual interface
*
* @add_key: add a key with the given parameters. @mac_addr will be %NULL
* when adding a group key.
*
* @get_key: get information about the key with the given parameters.
* @mac_addr will be %NULL when requesting information for a group
* key. All pointers given to the @callback function need not be valid
* after it returns.
*
* @del_key: remove a key given the @mac_addr (%NULL for a group key)
* and @key_index
*
* @set_default_key: set the default key on an interface
*
* @add_beacon: Add a beacon with given parameters, @head, @interval
* and @dtim_period will be valid, @tail is optional.
* @set_beacon: Change the beacon parameters for an access point mode
* interface. This should reject the call when no beacon has been
* configured.
* @del_beacon: Remove beacon configuration and stop sending the beacon.
*
* @add_station: Add a new station.
*
* @del_station: Remove a station; @mac may be NULL to remove all stations.
*
* @change_station: Modify a given station.
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
enum nl80211_iftype type);
enum nl80211_iftype type, u32 *flags);
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type);
enum nl80211_iftype type, u32 *flags);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, u8 *mac_addr,
struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params);
int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac);
int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params);
int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_stats *stats);
};
#endif /* __NET_CFG80211_H */

View File

@ -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
* This structure describes most essential parameters needed
* to describe 802.11n HT characteristics in a BSS
*
* @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)
*/
enum ieee80211_phymode {
MODE_IEEE80211A,
MODE_IEEE80211B,
MODE_IEEE80211G,
/* keep last */
NUM_IEEE80211_MODES
};
/**
* struct ieee80211_hw_mode - PHY mode definition
*
* This structure describes the capabilities supported by the device
* in a single PHY mode.
*
* @mode: the PHY mode for this definition
* @num_channels: number of supported channels
* @channels: pointer to array of supported channels
* @num_rates: number of supported bitrates
* @rates: pointer to array of supported bitrates
* @list: internal
*/
struct ieee80211_hw_mode {
struct list_head list;
struct ieee80211_channel *channels;
struct ieee80211_rate *rates;
enum ieee80211_phymode mode;
int num_channels;
int num_rates;
struct ieee80211_ht_bss_info {
u8 primary_channel;
u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */
u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
};
/**
@ -208,6 +133,7 @@ struct ieee80211_tx_queue_stats_data {
* @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
* sent after a beacon
* @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
* @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU
*/
enum ieee80211_tx_queue {
IEEE80211_TX_QUEUE_DATA0,
@ -223,11 +149,12 @@ enum ieee80211_tx_queue {
* this struct need to have fixed values. As soon as it is removed, we can
* fix these entries. */
IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
IEEE80211_TX_QUEUE_BEACON = 7
IEEE80211_TX_QUEUE_BEACON = 7,
NUM_TX_DATA_QUEUES_AMPDU = 16
};
struct ieee80211_tx_queue_stats {
struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU];
};
struct ieee80211_low_level_stats {
@ -237,16 +164,56 @@ struct ieee80211_low_level_stats {
unsigned int dot11RTSSuccessCount;
};
/**
* enum ieee80211_bss_change - BSS change notification flags
*
* These flags are used with the bss_info_changed() callback
* to indicate which BSS parameter changed.
*
* @BSS_CHANGED_ASSOC: association status changed (associated/disassociated),
* also implies a change in the AID.
* @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed
* @BSS_CHANGED_ERP_PREAMBLE: preamble changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_ERP_CTS_PROT = 1<<1,
BSS_CHANGED_ERP_PREAMBLE = 1<<2,
};
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
* This structure keeps information about a BSS (and an association
* to that BSS) that can change during the lifetime of the BSS.
*
* @assoc: association status
* @aid: association ID number, valid only when @assoc is true
* @use_cts_prot: use CTS protection
* @use_short_preamble: use 802.11b short preamble
*/
struct ieee80211_bss_conf {
/* association related data */
bool assoc;
u16 aid;
/* erp related data */
bool use_cts_prot;
bool use_short_preamble;
};
/* Transmit control fields. This data structure is passed to low-level driver
* with each TX frame. The low-level driver is responsible for configuring
* the hardware to use given values (depending on what is supported). */
struct ieee80211_tx_control {
int tx_rate; /* Transmit rate, given as the hw specific value for the
* rate (from struct ieee80211_rate) */
int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
* specific value for the rate (from
* struct ieee80211_rate) */
struct ieee80211_vif *vif;
struct ieee80211_rate *tx_rate;
/* Transmit rate for RTS/CTS frame */
struct ieee80211_rate *rts_cts_rate;
/* retry rate for the last retries */
struct ieee80211_rate *alt_retry_rate;
#define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for
* this frame */
@ -265,10 +232,16 @@ struct ieee80211_tx_control {
#define IEEE80211_TXCTL_REQUEUE (1<<7)
#define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of
* the frame */
#define IEEE80211_TXCTL_SHORT_PREAMBLE (1<<9)
#define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send
* using the through
* set_retry_limit configured
* long retry value */
#define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */
#define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM
* beacon */
#define IEEE80211_TXCTL_AMPDU (1<<13) /* this frame should be sent
* as part of an A-MPDU */
u32 flags; /* tx control flags defined
* above */
u8 key_idx; /* keyidx from hw->set_key(), undefined if
@ -276,22 +249,12 @@ struct ieee80211_tx_control {
u8 retry_limit; /* 1 = only first attempt, 2 = one retry, ..
* This could be used when set_retry_limit
* is not implemented by the driver */
u8 power_level; /* per-packet transmit power level, in dBm */
u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
u8 icv_len; /* length of the ICV/MIC field in octets */
u8 iv_len; /* length of the IV field in octets */
u8 queue; /* hardware queue to use for this frame;
* 0 = highest, hw->queues-1 = lowest */
struct ieee80211_rate *rate; /* internal 80211.o rate */
struct ieee80211_rate *rts_rate; /* internal 80211.o rate
* for RTS/CTS */
int alt_retry_rate; /* retry rate for the last retries, given as the
* hw specific value for the rate (from
* struct ieee80211_rate). To be used to limit
* packet dropping when probing higher rates, if hw
* supports multiple retry rates. -1 = not used */
int type; /* internal */
int ifindex; /* internal */
};
@ -312,6 +275,8 @@ struct ieee80211_tx_control {
* the frame.
* @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
* the frame.
* @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
* is valid.
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
@ -321,6 +286,7 @@ enum mac80211_rx_flags {
RX_FLAG_IV_STRIPPED = 1<<4,
RX_FLAG_FAILED_FCS_CRC = 1<<5,
RX_FLAG_FAILED_PLCP_CRC = 1<<6,
RX_FLAG_TSFT = 1<<7,
};
/**
@ -330,26 +296,24 @@ enum mac80211_rx_flags {
* supported by hardware) to the 802.11 code with each received
* frame.
* @mactime: MAC timestamp as defined by 802.11
* @band: the active band when this frame was received
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
* @channel: channel the radio was tuned to
* @phymode: active PHY mode
* @ssi: signal strength when receiving this frame
* @signal: used as 'qual' in statistics reporting
* @noise: PHY noise when receiving this frame
* @antenna: antenna used
* @rate: data rate
* @rate_idx: index of data rate into band's supported rates
* @flag: %RX_FLAG_*
*/
struct ieee80211_rx_status {
u64 mactime;
enum ieee80211_band band;
int freq;
int channel;
enum ieee80211_phymode phymode;
int ssi;
int signal;
int noise;
int antenna;
int rate;
int rate_idx;
int flag;
};
@ -360,12 +324,14 @@ struct ieee80211_rx_status {
*
* @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
* because the destination STA was in powersave mode.
*
* @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
* @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
* is for the whole aggregation.
*/
enum ieee80211_tx_status_flags {
IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
IEEE80211_TX_STATUS_ACK = 1<<1,
IEEE80211_TX_STATUS_AMPDU = 1<<2,
};
/**
@ -376,24 +342,25 @@ enum ieee80211_tx_status_flags {
*
* @control: a copy of the &struct ieee80211_tx_control passed to the driver
* in the tx() callback.
*
* @flags: transmit status flags, defined above
*
* @ack_signal: signal strength of the ACK frame
*
* @retry_count: number of retries
* @excessive_retries: set to 1 if the frame was retried many times
* but not acknowledged
*
* @retry_count: number of retries
*
* @ampdu_ack_len: number of aggregated frames.
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
* @ampdu_ack_map: block ack bit map for the aggregation.
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
* @ack_signal: signal strength of the ACK frame
* @queue_length: ?? REMOVE
* @queue_number: ?? REMOVE
*/
struct ieee80211_tx_status {
struct ieee80211_tx_control control;
u8 flags;
bool excessive_retries;
u8 retry_count;
bool excessive_retries;
u8 ampdu_ack_len;
u64 ampdu_ack_map;
int ack_signal;
int queue_length;
int queue_number;
@ -406,11 +373,12 @@ struct ieee80211_tx_status {
*
* @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
* @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
*
* @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
*/
enum ieee80211_conf_flags {
IEEE80211_CONF_SHORT_SLOT_TIME = 1<<0,
IEEE80211_CONF_RADIOTAP = 1<<1,
IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0),
IEEE80211_CONF_RADIOTAP = (1<<1),
IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2),
};
/**
@ -420,38 +388,32 @@ enum ieee80211_conf_flags {
*
* @radio_enabled: when zero, driver is required to switch off the radio.
* TODO make a flag
* @channel: IEEE 802.11 channel number
* @freq: frequency in MHz
* @channel_val: hardware specific channel value for the channel
* @phymode: PHY mode to activate (REMOVE)
* @chan: channel to switch to, pointer to the channel information
* @mode: pointer to mode definition
* @regulatory_domain: ??
* @beacon_int: beacon interval (TODO make interface config)
* @flags: configuration flags defined above
* @power_level: transmit power limit for current regulatory domain in dBm
* @antenna_max: maximum antenna gain
* @power_level: requested transmit power (in dBm)
* @max_antenna_gain: maximum antenna gain (in dBi)
* @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
* 1/2: antenna 0/1
* @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
* @ht_conf: describes current self configuration of 802.11n HT capabilies
* @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
* @channel: the channel to tune to
*/
struct ieee80211_conf {
int channel; /* IEEE 802.11 channel number */
int freq; /* MHz */
int channel_val; /* hw specific value for the channel */
enum ieee80211_phymode phymode;
struct ieee80211_channel *chan;
struct ieee80211_hw_mode *mode;
unsigned int regulatory_domain;
int radio_enabled;
int beacon_int;
u32 flags;
u8 power_level;
u8 antenna_max;
int power_level;
int max_antenna_gain;
u8 antenna_sel_tx;
u8 antenna_sel_rx;
struct ieee80211_channel *channel;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
};
/**
@ -479,14 +441,28 @@ enum ieee80211_if_types {
IEEE80211_IF_TYPE_VLAN,
};
/**
* struct ieee80211_vif - per-interface data
*
* Data in this structure is continually present for driver
* use during the life of a virtual interface.
*
* @type: type of this virtual interface
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
struct ieee80211_vif {
enum ieee80211_if_types type;
/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
/**
* struct ieee80211_if_init_conf - initial configuration of an interface
*
* @if_id: internal interface ID. This number has no particular meaning to
* drivers and the only allowed usage is to pass it to
* ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
* This field is not valid for monitor interfaces
* (interfaces of %IEEE80211_IF_TYPE_MNTR type).
* @vif: pointer to a driver-use per-interface structure. The pointer
* itself is also used for various functions including
* ieee80211_beacon_get() and ieee80211_get_buffered_bc().
* @type: one of &enum ieee80211_if_types constants. Determines the type of
* added/removed interface.
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
@ -503,8 +479,8 @@ enum ieee80211_if_types {
* in pure monitor mode.
*/
struct ieee80211_if_init_conf {
int if_id;
enum ieee80211_if_types type;
struct ieee80211_vif *vif;
void *mac_addr;
};
@ -597,9 +573,6 @@ struct ieee80211_key_conf {
u8 key[0];
};
#define IEEE80211_SEQ_COUNTER_RX 0
#define IEEE80211_SEQ_COUNTER_TX 1
/**
* enum set_key_cmd - key command
*
@ -659,15 +632,19 @@ enum sta_notify_cmd {
* %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because
* otherwise the stack will not know when the DTIM beacon was sent.
*
* @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED:
* Channels are already configured to the default regulatory domain
* specified in the device's EEPROM
* @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE:
* Hardware is not capable of short slot operation on the 2.4 GHz band.
*
* @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
* Hardware is not capable of receiving frames with short preamble on
* the 2.4 GHz band.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0,
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED = 1<<3,
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4,
};
/**
@ -679,7 +656,8 @@ enum ieee80211_hw_flags {
* @wiphy: This points to the &struct wiphy allocated for this
* 802.11 PHY. You must fill in the @perm_addr and @dev
* members of this structure using SET_IEEE80211_DEV()
* and SET_IEEE80211_PERM_ADDR().
* and SET_IEEE80211_PERM_ADDR(). Additionally, all supported
* bands (with channels, bitrates) are registered here.
*
* @conf: &struct ieee80211_conf, device configuration, don't use.
*
@ -706,15 +684,24 @@ enum ieee80211_hw_flags {
*
* @queues: number of available hardware transmit queues for
* data packets. WMM/QoS requires at least four.
*
* @rate_control_algorithm: rate control algorithm for this hardware.
* If unset (NULL), the default algorithm will be used. Must be
* set before calling ieee80211_register_hw().
*
* @vif_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_vif.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
struct wiphy *wiphy;
struct workqueue_struct *workqueue;
const char *rate_control_algorithm;
void *priv;
u32 flags;
unsigned int extra_tx_headroom;
int channel_change_time;
int vif_data_size;
u8 queues;
s8 max_rssi;
s8 max_signal;
@ -854,19 +841,22 @@ enum ieee80211_filter_flags {
};
/**
* enum ieee80211_erp_change_flags - erp change flags
* enum ieee80211_ampdu_mlme_action - A-MPDU actions
*
* 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
* 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,
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 */

View File

@ -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 */

View File

@ -1,6 +1,5 @@
config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
depends on EXPERIMENTAL
select CRYPTO
select CRYPTO_ECB
select CRYPTO_ARC4
@ -13,6 +12,75 @@ config MAC80211
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
@ -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

View File

@ -1,10 +1,15 @@
obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
obj-$(CONFIG_MAC80211) += mac80211.o
mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
# objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
mac80211-objs := \
# build helper for PID algorithm
rc-pid-y := $(rc80211_pid-y)
rc-pid-m := rc80211_pid.o
# mac80211 objects
mac80211-y := \
ieee80211.o \
ieee80211_ioctl.o \
sta_info.o \
@ -14,7 +19,6 @@ mac80211-objs := \
ieee80211_iface.o \
ieee80211_rate.o \
michael.o \
regdomain.o \
tkip.o \
aes_ccm.o \
cfg.o \
@ -22,5 +26,22 @@ mac80211-objs := \
tx.o \
key.o \
util.o \
event.o \
$(mac80211-objs-y)
event.o
mac80211-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
mac80211-$(CONFIG_NET_SCHED) += wme.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
debugfs.o \
debugfs_sta.o \
debugfs_netdev.o \
debugfs_key.o
# Build rate control algorithm(s)
CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE
mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID))
# Modular rate algorithms are assigned to mac80211-m - make separate modules
obj-m += $(mac80211-m)

View File

@ -7,10 +7,10 @@
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
#include <asm/scatterlist.h>
#include <net/mac80211.h>
#include "ieee80211_key.h"
@ -63,7 +63,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
s_0 = scratch + AES_BLOCK_LEN;
e = scratch + 2 * AES_BLOCK_LEN;
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
@ -102,7 +102,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
s_0 = scratch + AES_BLOCK_LEN;
a = scratch + 2 * AES_BLOCK_LEN;
num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);

View File

@ -1,16 +1,20 @@
/*
* mac80211 configuration hooks for cfg80211
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*
* This file is GPLv2 as found in COPYING.
*/
#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <net/net_namespace.h>
#include <linux/rcupdate.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "cfg.h"
#include "ieee80211_rate.h"
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@ -30,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
}
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
enum nl80211_iftype type)
enum nl80211_iftype type, u32 *flags)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
enum ieee80211_if_types itype;
struct net_device *dev;
struct ieee80211_sub_if_data *sdata;
int err;
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
return -ENODEV;
@ -42,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
if (itype == IEEE80211_IF_TYPE_INVALID)
return -EINVAL;
return ieee80211_if_add(local->mdev, name, NULL, itype);
err = ieee80211_if_add(local->mdev, name, &dev, itype);
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
return err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata->u.mntr_flags = *flags;
return 0;
}
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
@ -55,7 +68,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
return -ENODEV;
/* we're under RTNL */
dev = __dev_get_by_index(ifindex);
dev = __dev_get_by_index(&init_net, ifindex);
if (!dev)
return 0;
@ -65,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
}
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type)
enum nl80211_iftype type, u32 *flags)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev;
@ -76,7 +89,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
return -ENODEV;
/* we're under RTNL */
dev = __dev_get_by_index(ifindex);
dev = __dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENODEV;
@ -89,12 +102,551 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_VLAN)
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
return -EOPNOTSUPP;
ieee80211_if_reinit(dev);
ieee80211_if_set_type(dev, itype);
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
return 0;
sdata->u.mntr_flags = *flags;
return 0;
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr,
struct key_params *params)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL;
enum ieee80211_key_alg alg;
int ret;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
alg = ALG_WEP;
break;
case WLAN_CIPHER_SUITE_TKIP:
alg = ALG_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
alg = ALG_CCMP;
break;
default:
return -EINVAL;
}
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
return -ENOENT;
}
ret = 0;
if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
params->key_len, params->key))
ret = -ENOMEM;
if (sta)
sta_info_put(sta);
return ret;
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
int ret;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
return -ENOENT;
ret = 0;
if (sta->key)
ieee80211_key_free(sta->key);
else
ret = -ENOENT;
sta_info_put(sta);
return ret;
}
if (!sdata->keys[key_idx])
return -ENOENT;
ieee80211_key_free(sdata->keys[key_idx]);
return 0;
}
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta = NULL;
u8 seq[6] = {0};
struct key_params params;
struct ieee80211_key *key;
u32 iv32;
u16 iv16;
int err = -ENOENT;
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
goto out;
key = sta->key;
} else
key = sdata->keys[key_idx];
if (!key)
goto out;
memset(&params, 0, sizeof(params));
switch (key->conf.alg) {
case ALG_TKIP:
params.cipher = WLAN_CIPHER_SUITE_TKIP;
iv32 = key->u.tkip.iv32;
iv16 = key->u.tkip.iv16;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
sdata->local->ops->get_tkip_seq)
sdata->local->ops->get_tkip_seq(
local_to_hw(sdata->local),
key->conf.hw_key_idx,
&iv32, &iv16);
seq[0] = iv16 & 0xff;
seq[1] = (iv16 >> 8) & 0xff;
seq[2] = iv32 & 0xff;
seq[3] = (iv32 >> 8) & 0xff;
seq[4] = (iv32 >> 16) & 0xff;
seq[5] = (iv32 >> 24) & 0xff;
params.seq = seq;
params.seq_len = 6;
break;
case ALG_CCMP:
params.cipher = WLAN_CIPHER_SUITE_CCMP;
seq[0] = key->u.ccmp.tx_pn[5];
seq[1] = key->u.ccmp.tx_pn[4];
seq[2] = key->u.ccmp.tx_pn[3];
seq[3] = key->u.ccmp.tx_pn[2];
seq[4] = key->u.ccmp.tx_pn[1];
seq[5] = key->u.ccmp.tx_pn[0];
params.seq = seq;
params.seq_len = 6;
break;
case ALG_WEP:
if (key->conf.keylen == 5)
params.cipher = WLAN_CIPHER_SUITE_WEP40;
else
params.cipher = WLAN_CIPHER_SUITE_WEP104;
break;
}
params.key = key->conf.key;
params.key_len = key->conf.keylen;
callback(cookie, &params);
err = 0;
out:
if (sta)
sta_info_put(sta);
return err;
}
static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
{
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_key(sdata, key_idx);
return 0;
}
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_stats *stats)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
sta = sta_info_get(local, mac);
if (!sta)
return -ENOENT;
/* XXX: verify sta->dev == dev */
stats->filled = STATION_STAT_INACTIVE_TIME |
STATION_STAT_RX_BYTES |
STATION_STAT_TX_BYTES;
stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
stats->rx_bytes = sta->rx_bytes;
stats->tx_bytes = sta->tx_bytes;
sta_info_put(sta);
return 0;
}
/*
* This handles both adding a beacon and setting new beacon info
*/
static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
struct beacon_parameters *params)
{
struct beacon_data *new, *old;
int new_head_len, new_tail_len;
int size;
int err = -EINVAL;
old = sdata->u.ap.beacon;
/* head must not be zero-length */
if (params->head && !params->head_len)
return -EINVAL;
/*
* This is a kludge. beacon interval should really be part
* of the beacon information.
*/
if (params->interval) {
sdata->local->hw.conf.beacon_int = params->interval;
if (ieee80211_hw_config(sdata->local))
return -EINVAL;
/*
* We updated some parameter so if below bails out
* it's not an error.
*/
err = 0;
}
/* Need to have a beacon head if we don't have one yet */
if (!params->head && !old)
return err;
/* sorry, no way to start beaconing without dtim period */
if (!params->dtim_period && !old)
return err;
/* new or old head? */
if (params->head)
new_head_len = params->head_len;
else
new_head_len = old->head_len;
/* new or old tail? */
if (params->tail || !old)
/* params->tail_len will be zero for !params->tail */
new_tail_len = params->tail_len;
else
new_tail_len = old->tail_len;
size = sizeof(*new) + new_head_len + new_tail_len;
new = kzalloc(size, GFP_KERNEL);
if (!new)
return -ENOMEM;
/* start filling the new info now */
/* new or old dtim period? */
if (params->dtim_period)
new->dtim_period = params->dtim_period;
else
new->dtim_period = old->dtim_period;
/*
* pointers go into the block we allocated,
* memory is | beacon_data | head | tail |
*/
new->head = ((u8 *) new) + sizeof(*new);
new->tail = new->head + new_head_len;
new->head_len = new_head_len;
new->tail_len = new_tail_len;
/* copy in head */
if (params->head)
memcpy(new->head, params->head, new_head_len);
else
memcpy(new->head, old->head, new_head_len);
/* copy in optional tail */
if (params->tail)
memcpy(new->tail, params->tail, new_tail_len);
else
if (old)
memcpy(new->tail, old->tail, new_tail_len);
rcu_assign_pointer(sdata->u.ap.beacon, new);
synchronize_rcu();
kfree(old);
return ieee80211_if_config_beacon(sdata->dev);
}
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct beacon_data *old;
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
if (old)
return -EALREADY;
return ieee80211_config_beacon(sdata, params);
}
static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct beacon_data *old;
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
if (!old)
return -ENOENT;
return ieee80211_config_beacon(sdata, params);
}
static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct beacon_data *old;
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
if (!old)
return -ENOENT;
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
synchronize_rcu();
kfree(old);
return ieee80211_if_config_beacon(dev);
}
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
u8 da[ETH_ALEN]; /* broadcast */
u8 sa[ETH_ALEN]; /* STA addr */
__be16 len; /* 6 */
u8 dsap; /* 0 */
u8 ssap; /* 0 */
u8 control;
u8 xid_info[3];
} __attribute__ ((packed));
static void ieee80211_send_layer2_update(struct sta_info *sta)
{
struct iapp_layer2_update *msg;
struct sk_buff *skb;
/* Send Level 2 Update Frame to update forwarding tables in layer 2
* bridge devices */
skb = dev_alloc_skb(sizeof(*msg));
if (!skb)
return;
msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
memset(msg->da, 0xff, ETH_ALEN);
memcpy(msg->sa, sta->addr, ETH_ALEN);
msg->len = htons(6);
msg->dsap = 0;
msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
msg->control = 0xaf; /* XID response lsb.1111F101.
* F=0 (no poll command; unsolicited frame) */
msg->xid_info[0] = 0x81; /* XID format identifier */
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
skb->dev = sta->dev;
skb->protocol = eth_type_trans(skb, sta->dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
}
static void sta_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta,
struct station_parameters *params)
{
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
if (params->station_flags & STATION_FLAG_AUTHORIZED)
sta->flags |= WLAN_STA_AUTHORIZED;
sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
sta->flags |= WLAN_STA_SHORT_PREAMBLE;
sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME;
}
if (params->aid) {
sta->aid = params->aid;
if (sta->aid > IEEE80211_MAX_AID)
sta->aid = 0; /* XXX: should this be an error? */
}
if (params->listen_interval >= 0)
sta->listen_interval = params->listen_interval;
if (params->supported_rates) {
rates = 0;
sband = local->hw.wiphy->bands[local->oper_channel->band];
for (i = 0; i < params->supported_rates_len; i++) {
int rate = (params->supported_rates[i] & 0x7f) * 5;
for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
}
}
sta->supp_rates[local->oper_channel->band] = rates;
}
}
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
/* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev))
return -ENETDOWN;
/* XXX: get sta belonging to dev */
sta = sta_info_get(local, mac);
if (sta) {
sta_info_put(sta);
return -EEXIST;
}
if (params->vlan) {
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sta = sta_info_add(local, dev, mac, GFP_KERNEL);
if (!sta)
return -ENOMEM;
sta->dev = sdata->dev;
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
sdata->vif.type == IEEE80211_IF_TYPE_AP)
ieee80211_send_layer2_update(sta);
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta_apply_parameters(local, sta, params);
rate_control_rate_init(sta, local);
sta_info_put(sta);
return 0;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
if (mac) {
/* XXX: get sta belonging to dev */
sta = sta_info_get(local, mac);
if (!sta)
return -ENOENT;
sta_info_free(sta);
sta_info_put(sta);
} else
sta_info_flush(local, dev);
return 0;
}
static int ieee80211_change_station(struct wiphy *wiphy,
struct net_device *dev,
u8 *mac,
struct station_parameters *params)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *vlansdata;
/* XXX: get sta belonging to dev */
sta = sta_info_get(local, mac);
if (!sta)
return -ENOENT;
if (params->vlan && params->vlan != sta->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
sta->dev = params->vlan;
ieee80211_send_layer2_update(sta);
}
sta_apply_parameters(local, sta, params);
sta_info_put(sta);
return 0;
}
@ -102,4 +654,15 @@ struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
.change_virtual_intf = ieee80211_change_iface,
.add_key = ieee80211_add_key,
.del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
.add_beacon = ieee80211_add_beacon,
.set_beacon = ieee80211_set_beacon,
.del_beacon = ieee80211_del_beacon,
.add_station = ieee80211_add_station,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
.get_station = ieee80211_get_station,
};

View File

@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file)
return 0;
}
static const char *ieee80211_mode_str(int mode)
{
switch (mode) {
case MODE_IEEE80211A:
return "IEEE 802.11a";
case MODE_IEEE80211B:
return "IEEE 802.11b";
case MODE_IEEE80211G:
return "IEEE 802.11g";
default:
return "UNKNOWN";
}
}
static ssize_t modes_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
struct ieee80211_hw_mode *mode;
char buf[150], *p = buf;
/* FIXME: locking! */
list_for_each_entry(mode, &local->modes_list, list) {
p += scnprintf(p, sizeof(buf)+buf-p,
"%s\n", ieee80211_mode_str(mode->mode));
}
return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
}
static const struct file_operations modes_ops = {
.read = modes_read,
.open = mac80211_open_file_generic,
};
#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
@ -80,10 +45,8 @@ static const struct file_operations name## _ops = { \
local->debugfs.name = NULL;
DEBUGFS_READONLY_FILE(channel, 20, "%d",
local->hw.conf.channel);
DEBUGFS_READONLY_FILE(frequency, 20, "%d",
local->hw.conf.freq);
local->hw.conf.channel->center_freq);
DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
local->hw.conf.antenna_sel_tx);
DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
local->long_retry_limit);
DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
local->total_ps_buffered);
DEBUGFS_READONLY_FILE(mode, 20, "%s",
ieee80211_mode_str(local->hw.conf.phymode));
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
local->wep_iv & 0xffffff);
DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
local->debugfs.stations = debugfs_create_dir("stations", phyd);
local->debugfs.keys = debugfs_create_dir("keys", phyd);
DEBUGFS_ADD(channel);
DEBUGFS_ADD(frequency);
DEBUGFS_ADD(antenna_sel_tx);
DEBUGFS_ADD(antenna_sel_rx);
@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(short_retry_limit);
DEBUGFS_ADD(long_retry_limit);
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(mode);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(modes);
statsd = debugfs_create_dir("statistics", phyd);
local->debugfs.statistics = statsd;
@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
void debugfs_hw_del(struct ieee80211_local *local)
{
DEBUGFS_DEL(channel);
DEBUGFS_DEL(frequency);
DEBUGFS_DEL(antenna_sel_tx);
DEBUGFS_DEL(antenna_sel_rx);
@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
DEBUGFS_DEL(short_retry_limit);
DEBUGFS_DEL(long_retry_limit);
DEBUGFS_DEL(total_ps_buffered);
DEBUGFS_DEL(mode);
DEBUGFS_DEL(wep_iv);
DEBUGFS_DEL(modes);
DEBUGFS_STATS_DEL(transmitted_fragment_count);
DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);

View File

@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
struct sta_info *sta)
{
char buf[50];
DECLARE_MAC_BUF(mac);
if (!key->debugfs.dir)
return;
sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr));
sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr));
key->debugfs.stalink =
debugfs_create_symlink("station", key->debugfs.dir, buf);
}

View File

@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, char *buf, \
int buflen) \
{ \
return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\
DECLARE_MAC_BUF(mac); \
return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
}
#define __IEEE80211_IF_FILE(name) \
@ -90,8 +91,6 @@ static const struct file_operations name##_ops = { \
/* common attributes */
IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
IEEE80211_IF_FILE(eapol, eapol, DEC);
IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
/* STA/IBSS attributes */
IEEE80211_IF_FILE(state, u.sta.state, DEC);
@ -118,13 +117,12 @@ static ssize_t ieee80211_if_fmt_flags(
sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : "");
sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
}
__IEEE80211_IF_FILE(flags);
/* AP attributes */
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
@ -138,26 +136,6 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
}
__IEEE80211_IF_FILE(num_buffered_multicast);
static ssize_t ieee80211_if_fmt_beacon_head_len(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
if (sdata->u.ap.beacon_head)
return scnprintf(buf, buflen, "%d\n",
sdata->u.ap.beacon_head_len);
return scnprintf(buf, buflen, "\n");
}
__IEEE80211_IF_FILE(beacon_head_len);
static ssize_t ieee80211_if_fmt_beacon_tail_len(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
if (sdata->u.ap.beacon_tail)
return scnprintf(buf, buflen, "%d\n",
sdata->u.ap.beacon_tail_len);
return scnprintf(buf, buflen, "\n");
}
__IEEE80211_IF_FILE(beacon_tail_len);
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@ -169,8 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(eapol, sta);
DEBUGFS_ADD(ieee8021_x, sta);
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(prev_bssid, sta);
@ -191,25 +167,18 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_use, ap);
DEBUGFS_ADD(drop_unencrypted, ap);
DEBUGFS_ADD(eapol, ap);
DEBUGFS_ADD(ieee8021_x, ap);
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_period, ap);
DEBUGFS_ADD(dtim_count, ap);
DEBUGFS_ADD(num_beacons, ap);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(num_buffered_multicast, ap);
DEBUGFS_ADD(beacon_head_len, ap);
DEBUGFS_ADD(beacon_tail_len, ap);
}
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_use, wds);
DEBUGFS_ADD(drop_unencrypted, wds);
DEBUGFS_ADD(eapol, wds);
DEBUGFS_ADD(ieee8021_x, wds);
DEBUGFS_ADD(peer, wds);
}
@ -217,8 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_use, vlan);
DEBUGFS_ADD(drop_unencrypted, vlan);
DEBUGFS_ADD(eapol, vlan);
DEBUGFS_ADD(ieee8021_x, vlan);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@ -230,7 +197,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
if (!sdata->debugfsdir)
return;
switch (sdata->type) {
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
add_sta_files(sdata);
@ -262,8 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(channel_use, sta);
DEBUGFS_DEL(drop_unencrypted, sta);
DEBUGFS_DEL(eapol, sta);
DEBUGFS_DEL(ieee8021_x, sta);
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
DEBUGFS_DEL(prev_bssid, sta);
@ -284,25 +249,18 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(channel_use, ap);
DEBUGFS_DEL(drop_unencrypted, ap);
DEBUGFS_DEL(eapol, ap);
DEBUGFS_DEL(ieee8021_x, ap);
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_period, ap);
DEBUGFS_DEL(dtim_count, ap);
DEBUGFS_DEL(num_beacons, ap);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(num_buffered_multicast, ap);
DEBUGFS_DEL(beacon_head_len, ap);
DEBUGFS_DEL(beacon_tail_len, ap);
}
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(channel_use, wds);
DEBUGFS_DEL(drop_unencrypted, wds);
DEBUGFS_DEL(eapol, wds);
DEBUGFS_DEL(ieee8021_x, wds);
DEBUGFS_DEL(peer, wds);
}
@ -310,8 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(channel_use, vlan);
DEBUGFS_DEL(drop_unencrypted, vlan);
DEBUGFS_DEL(eapol, vlan);
DEBUGFS_DEL(ieee8021_x, vlan);
}
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
@ -361,7 +317,7 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
{
del_files(sdata, sdata->type);
del_files(sdata, sdata->vif.type);
debugfs_remove(sdata->debugfsdir);
sdata->debugfsdir = NULL;
}

View File

@ -33,28 +33,19 @@ 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_WR(name) \
static const struct file_operations sta_ ##name## _ops = { \
.read = sta_##name##_read, \
.write = sta_##name##_write, \
.open = mac80211_open_file_generic, \
}
#define STA_FILE(name, field, format) \
STA_READ_##format(name, field) \
STA_OPS(name)
@ -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;

View File

@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
{
union iwreq_data wrqu;
char *buf = kmalloc(128, GFP_ATOMIC);
DECLARE_MAC_BUF(mac);
if (buf) {
/* TODO: needed parameters: count, key type, TSC */
sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
"keyid=%d %scast addr=" MAC_FMT ")",
"keyid=%d %scast addr=%s)",
keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
MAC_ARG(hdr->addr2));
print_mac(mac, hdr->addr2));
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = strlen(buf);
wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -37,8 +37,6 @@
struct ieee80211_local;
#define BIT(x) (1 << (x))
#define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
/* Maximum number of broadcast/multicast frames to buffer when some of the
@ -81,8 +79,7 @@ struct ieee80211_sta_bss {
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
u16 capability; /* host byte order */
int hw_mode;
int channel;
enum ieee80211_band band;
int freq;
int rssi, signal, noise;
u8 *wpa_ie;
@ -91,6 +88,8 @@ struct ieee80211_sta_bss {
size_t rsn_ie_len;
u8 *wmm_ie;
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
@ -109,9 +108,17 @@ struct ieee80211_sta_bss {
};
typedef enum {
TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
} ieee80211_txrx_result;
typedef unsigned __bitwise__ ieee80211_tx_result;
#define TX_CONTINUE ((__force ieee80211_tx_result) 0u)
#define TX_DROP ((__force ieee80211_tx_result) 1u)
#define TX_QUEUED ((__force ieee80211_tx_result) 2u)
typedef unsigned __bitwise__ ieee80211_rx_result;
#define RX_CONTINUE ((__force ieee80211_rx_result) 0u)
#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u)
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
#define RX_QUEUED ((__force ieee80211_rx_result) 3u)
/* flags used in struct ieee80211_txrx_data.flags */
/* whether the MSDU was fragmented */
@ -123,6 +130,8 @@ typedef enum {
/* frame is destined to interface currently processed (incl. multicast frames) */
#define IEEE80211_TXRXD_RXRA_MATCH BIT(5)
#define IEEE80211_TXRXD_TX_INJECTED BIT(6)
#define IEEE80211_TXRXD_RX_AMSDU BIT(7)
#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8)
struct ieee80211_txrx_data {
struct sk_buff *skb;
struct net_device *dev;
@ -135,13 +144,12 @@ struct ieee80211_txrx_data {
union {
struct {
struct ieee80211_tx_control *control;
struct ieee80211_hw_mode *mode;
struct ieee80211_channel *channel;
struct ieee80211_rate *rate;
/* use this rate (if set) for last fragment; rate can
* be set to lower rate for the first fragments, e.g.,
* when using CTS protection with IEEE 802.11g. */
struct ieee80211_rate *last_frag_rate;
int last_frag_hwrate;
/* Extra fragments (in addition to the first fragment
* in skb) */
@ -150,6 +158,7 @@ struct ieee80211_txrx_data {
} tx;
struct {
struct ieee80211_rx_status *status;
struct ieee80211_rate *rate;
int sent_ps_buffered;
int queue;
int load;
@ -163,6 +172,8 @@ struct ieee80211_txrx_data {
#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
#define IEEE80211_TXPD_REQUEUE BIT(2)
#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
#define IEEE80211_TXPD_AMPDU BIT(4)
/* Stored in sk_buff->cb */
struct ieee80211_tx_packet_data {
int ifindex;
@ -176,21 +187,18 @@ struct ieee80211_tx_stored_packet {
struct sk_buff *skb;
int num_extra_frag;
struct sk_buff **extra_frag;
int last_frag_rateidx;
int last_frag_hwrate;
struct ieee80211_rate *last_frag_rate;
unsigned int last_frag_rate_ctrl_probe;
};
typedef ieee80211_txrx_result (*ieee80211_tx_handler)
(struct ieee80211_txrx_data *tx);
typedef ieee80211_txrx_result (*ieee80211_rx_handler)
(struct ieee80211_txrx_data *rx);
struct beacon_data {
u8 *head, *tail;
int head_len, tail_len;
int dtim_period;
};
struct ieee80211_if_ap {
u8 *beacon_head, *beacon_tail;
int beacon_head_len, beacon_tail_len;
struct beacon_data *beacon;
struct list_head vlans;
@ -203,7 +211,7 @@ struct ieee80211_if_ap {
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
atomic_t num_sta_ps; /* number of stations in PS mode */
struct sk_buff_head ps_bc_buf;
int dtim_period, dtim_count;
int dtim_count;
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
int num_beacons; /* number of TXed beacon frames for this BSS */
@ -232,6 +240,7 @@ struct ieee80211_if_vlan {
#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
struct ieee80211_if_sta {
enum {
IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
@ -243,6 +252,8 @@ struct ieee80211_if_sta {
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
u16 aid;
u16 ap_capab, capab;
u8 *extra_ie; /* to be added to the end of AssocReq */
@ -261,7 +272,6 @@ struct ieee80211_if_sta {
unsigned long request;
struct sk_buff_head skb_queue;
int key_management_enabled;
unsigned long last_probe;
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
@ -273,7 +283,7 @@ struct ieee80211_if_sta {
unsigned long ibss_join_req;
struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
u32 supp_rates_bits;
u32 supp_rates_bits[IEEE80211_NUM_BANDS];
int wmm_last_param_set;
};
@ -282,15 +292,10 @@ struct ieee80211_if_sta {
/* flags used in struct ieee80211_sub_if_data.flags */
#define IEEE80211_SDATA_ALLMULTI BIT(0)
#define IEEE80211_SDATA_PROMISC BIT(1)
#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */
/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon
* generator reports that there are no present stations that cannot support short
* preambles */
#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3)
#define IEEE80211_SDATA_USERSPACE_MLME BIT(4)
#define IEEE80211_SDATA_USERSPACE_MLME BIT(2)
#define IEEE80211_SDATA_OPERATING_GMODE BIT(3)
struct ieee80211_sub_if_data {
struct list_head list;
enum ieee80211_if_types type;
struct wireless_dev wdev;
@ -303,11 +308,11 @@ struct ieee80211_sub_if_data {
unsigned int flags;
int drop_unencrypted;
int eapol; /* 0 = process EAPOL frames as normal data frames,
* 1 = send EAPOL frames through wlan#ap to hostapd
* (default) */
int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
* port */
/*
* basic rates of this AP or the AP we're associated to
*/
u64 basic_rates;
u16 sequence;
@ -319,6 +324,15 @@ struct ieee80211_sub_if_data {
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
struct ieee80211_key *default_key;
/*
* BSS configuration for this interface.
*
* FIXME: I feel bad putting this here when we already have a
* bss pointer, but the bss pointer is just wrong when
* you have multiple virtual STA mode interfaces...
* This needs to be fixed.
*/
struct ieee80211_bss_conf bss_conf;
struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
union {
@ -326,6 +340,7 @@ struct ieee80211_sub_if_data {
struct ieee80211_if_wds wds;
struct ieee80211_if_vlan vlan;
struct ieee80211_if_sta sta;
u32 mntr_flags;
} u;
int channel_use;
int channel_use_raw;
@ -336,8 +351,6 @@ struct ieee80211_sub_if_data {
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *eapol;
struct dentry *ieee8021_x;
struct dentry *state;
struct dentry *bssid;
struct dentry *prev_bssid;
@ -356,30 +369,21 @@ struct ieee80211_sub_if_data {
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *eapol;
struct dentry *ieee8021_x;
struct dentry *num_sta_ps;
struct dentry *dtim_period;
struct dentry *dtim_count;
struct dentry *num_beacons;
struct dentry *force_unicast_rateidx;
struct dentry *max_ratectrl_rateidx;
struct dentry *num_buffered_multicast;
struct dentry *beacon_head_len;
struct dentry *beacon_tail_len;
} ap;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *eapol;
struct dentry *ieee8021_x;
struct dentry *peer;
} wds;
struct {
struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *eapol;
struct dentry *ieee8021_x;
} vlan;
struct {
struct dentry *mode;
@ -387,13 +391,23 @@ struct ieee80211_sub_if_data {
struct dentry *default_key;
} debugfs;
#endif
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
};
static inline
struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
{
return container_of(p, struct ieee80211_sub_if_data, vif);
}
#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
IEEE80211_DELBA_MSG = 3,
IEEE80211_ADDBA_MSG = 4,
};
struct ieee80211_local {
@ -404,12 +418,11 @@ struct ieee80211_local {
const struct ieee80211_ops *ops;
/* List of registered struct ieee80211_hw_mode */
struct list_head modes_list;
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
u8 wstats_flags;
@ -437,8 +450,8 @@ struct ieee80211_local {
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
unsigned long state[NUM_TX_DATA_QUEUES];
struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */
@ -446,11 +459,6 @@ struct ieee80211_local {
struct rate_control_ref *rate_ctrl;
/* Supported and basic rate filters for different modes. These are
* pointers to -1 terminated lists and rates in 100 kbps units. */
int *supp_rates[NUM_IEEE80211_MODES];
int *basic_rates[NUM_IEEE80211_MODES];
int rts_threshold;
int fragmentation_threshold;
int short_retry_limit; /* dot11ShortRetryLimit */
@ -464,29 +472,23 @@ struct ieee80211_local {
* deliver multicast frames both back to wireless
* media and to the local net stack */
ieee80211_rx_handler *rx_pre_handlers;
ieee80211_rx_handler *rx_handlers;
ieee80211_tx_handler *tx_handlers;
struct list_head interfaces;
int sta_scanning;
bool sta_sw_scanning;
bool sta_hw_scanning;
int scan_channel_idx;
enum ieee80211_band scan_band;
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
unsigned long last_scan_completed;
struct delayed_work scan_work;
struct net_device *scan_dev;
struct ieee80211_channel *oper_channel, *scan_channel;
struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head sta_bss_list;
struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
spinlock_t sta_bss_lock;
#define IEEE80211_SCAN_MATCH_SSID BIT(0)
#define IEEE80211_SCAN_WPA_ONLY BIT(1)
#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
int scan_flags;
/* SNMP counters */
/* dot11CountersTable */
@ -503,8 +505,9 @@ struct ieee80211_local {
#ifdef CONFIG_MAC80211_LEDS
int tx_led_counter, rx_led_counter;
struct led_trigger *tx_led, *rx_led, *assoc_led;
char tx_led_name[32], rx_led_name[32], assoc_led_name[32];
struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
char tx_led_name[32], rx_led_name[32],
assoc_led_name[32], radio_led_name[32];
#endif
u32 channel_use;
@ -549,14 +552,8 @@ struct ieee80211_local {
int wifi_wme_noack_test;
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
unsigned int enabled_modes; /* bitfield of allowed modes;
* (1 << MODE_*) */
unsigned int hw_modes; /* bitfield of supported hardware modes;
* (1 << MODE_*) */
#ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries {
struct dentry *channel;
struct dentry *frequency;
struct dentry *antenna_sel_tx;
struct dentry *antenna_sel_rx;
@ -566,9 +563,7 @@ struct ieee80211_local {
struct dentry *short_retry_limit;
struct dentry *long_retry_limit;
struct dentry *total_ps_buffered;
struct dentry *mode;
struct dentry *wep_iv;
struct dentry *modes;
struct dentry *statistics;
struct local_debugfsdentries_statsdentries {
struct dentry *transmitted_fragment_count;
@ -616,6 +611,12 @@ struct ieee80211_local {
#endif
};
/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
u8 ra[ETH_ALEN];
u16 tid;
};
static inline struct ieee80211_local *hw_to_local(
struct ieee80211_hw *hw)
{
@ -673,23 +674,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local,
read_unlock_bh(&local->sta_lock);
}
/**
* ieee80211_is_erp_rate - Check if a rate is an ERP rate
* @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
* @rate: Transmission rate to check, in 100 kbps
*
* Check if a given rate is an Extended Rate PHY (ERP) rate.
*/
static inline int ieee80211_is_erp_rate(int phymode, int rate)
{
if (phymode == MODE_IEEE80211G) {
if (rate != 10 && rate != 20 &&
rate != 55 && rate != 110)
return 1;
}
return 0;
}
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
{
return compare_ether_addr(raddr, addr) == 0 ||
@ -701,13 +685,12 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
int ieee80211_hw_config(struct ieee80211_local *local);
int ieee80211_if_config(struct net_device *dev);
int ieee80211_if_config_beacon(struct net_device *dev);
void ieee80211_prepare_rates(struct ieee80211_local *local,
struct ieee80211_hw_mode *mode);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
void ieee80211_if_setup(struct net_device *dev);
struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
int phymode, int hwrate);
int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap);
/* ieee80211_ioctl.c */
extern const struct iw_handler_def ieee80211_iw_handler_def;
@ -735,7 +718,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
/* ieee80211_ioctl.c */
int ieee80211_set_compression(struct ieee80211_local *local,
struct net_device *dev, struct sta_info *sta);
int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
int ieee80211_set_freq(struct ieee80211_local *local, int freq);
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
@ -749,7 +732,8 @@ 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,
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);
@ -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,

View File

@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
/* Default values for sub-interface parameters */
sdata->drop_unencrypted = 0;
sdata->eapol = 1;
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list);
@ -48,7 +47,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
int ret;
ASSERT_RTNL();
ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
name, ieee80211_if_setup);
if (!ndev)
return -ENOMEM;
@ -67,7 +66,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
ndev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = local->hw.wiphy;
sdata->type = IEEE80211_IF_TYPE_AP;
sdata->vif.type = IEEE80211_IF_TYPE_AP;
sdata->dev = ndev;
sdata->local = local;
ieee80211_if_sdata_init(sdata);
@ -99,7 +98,7 @@ fail:
void ieee80211_if_set_type(struct net_device *dev, int type)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int oldtype = sdata->type;
int oldtype = sdata->vif.type;
/*
* We need to call this function on the master interface
@ -117,7 +116,9 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
/* most have no BSS pointer */
sdata->bss = NULL;
sdata->type = type;
sdata->vif.type = type;
sdata->basic_rates = 0;
switch (type) {
case IEEE80211_IF_TYPE_WDS:
@ -127,7 +128,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
sdata->u.vlan.ap = NULL;
break;
case IEEE80211_IF_TYPE_AP:
sdata->u.ap.dtim_period = 2;
sdata->u.ap.force_unicast_rateidx = -1;
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@ -160,6 +160,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_IEEE80211_RADIOTAP;
dev->hard_start_xmit = ieee80211_monitor_start_xmit;
sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
MONITOR_FLAG_OTHER_BSS;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
@ -182,7 +184,7 @@ void ieee80211_if_reinit(struct net_device *dev)
ieee80211_if_sdata_deinit(sdata);
switch (sdata->type) {
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_INVALID:
/* cannot happen */
WARN_ON(1);
@ -208,8 +210,7 @@ void ieee80211_if_reinit(struct net_device *dev)
}
}
kfree(sdata->u.ap.beacon_head);
kfree(sdata->u.ap.beacon_tail);
kfree(sdata->u.ap.beacon);
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
@ -280,7 +281,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
ASSERT_RTNL();
list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
if ((sdata->type == id || id == -1) &&
if ((sdata->vif.type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 &&
sdata->dev != local->mdev) {
list_del_rcu(&sdata->list);

View File

@ -21,6 +21,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "ieee80211_led.h"
#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
@ -64,9 +65,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
sta = sta_info_get(local, sta_addr);
if (!sta) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
MAC_FMT "\n",
dev->name, MAC_ARG(sta_addr));
"%s\n",
dev->name, print_mac(mac, sta_addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
return -ENOENT;
@ -110,8 +112,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
return -EOPNOTSUPP;
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
if (ret)
return ret;
@ -127,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
switch (local->hw.conf.phymode) {
case MODE_IEEE80211A:
strcpy(name, "IEEE 802.11a");
break;
case MODE_IEEE80211B:
strcpy(name, "IEEE 802.11b");
break;
case MODE_IEEE80211G:
strcpy(name, "IEEE 802.11g");
break;
default:
strcpy(name, "IEEE 802.11");
break;
}
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)
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;
if (local->hw.conf.power_level != data->txpower.value) {
local->hw.conf.power_level = data->txpower.value;
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;

View File

@ -43,6 +43,16 @@ void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
led_trigger_event(local->assoc_led, LED_OFF);
}
void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
{
if (unlikely(!local->radio_led))
return;
if (enabled)
led_trigger_event(local->radio_led, LED_FULL);
else
led_trigger_event(local->radio_led, LED_OFF);
}
void ieee80211_led_init(struct ieee80211_local *local)
{
local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
@ -77,10 +87,25 @@ void ieee80211_led_init(struct ieee80211_local *local)
local->assoc_led = NULL;
}
}
local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
if (local->radio_led) {
snprintf(local->radio_led_name, sizeof(local->radio_led_name),
"%sradio", wiphy_name(local->hw.wiphy));
local->radio_led->name = local->radio_led_name;
if (led_trigger_register(local->radio_led)) {
kfree(local->radio_led);
local->radio_led = NULL;
}
}
}
void ieee80211_led_exit(struct ieee80211_local *local)
{
if (local->radio_led) {
led_trigger_unregister(local->radio_led);
kfree(local->radio_led);
}
if (local->assoc_led) {
led_trigger_unregister(local->assoc_led);
kfree(local->assoc_led);
@ -95,6 +120,16 @@ void ieee80211_led_exit(struct ieee80211_local *local)
}
}
char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
if (local->radio_led)
return local->radio_led_name;
return NULL;
}
EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);

View File

@ -16,6 +16,8 @@ extern void ieee80211_led_rx(struct ieee80211_local *local);
extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
extern void ieee80211_led_assoc(struct ieee80211_local *local,
bool associated);
extern void ieee80211_led_radio(struct ieee80211_local *local,
bool enabled);
extern void ieee80211_led_init(struct ieee80211_local *local);
extern void ieee80211_led_exit(struct ieee80211_local *local);
#else
@ -29,6 +31,10 @@ static inline void ieee80211_led_assoc(struct ieee80211_local *local,
bool associated)
{
}
static inline void ieee80211_led_radio(struct ieee80211_local *local,
bool enabled)
{
}
static inline void ieee80211_led_init(struct ieee80211_local *local)
{
}

View File

@ -21,17 +21,35 @@ struct rate_control_alg {
static LIST_HEAD(rate_ctrl_algs);
static DEFINE_MUTEX(rate_ctrl_mutex);
static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT;
module_param(ieee80211_default_rc_algo, charp, 0644);
MODULE_PARM_DESC(ieee80211_default_rc_algo,
"Default rate control algorithm for mac80211 to use");
int ieee80211_rate_control_register(struct rate_control_ops *ops)
{
struct rate_control_alg *alg;
if (!ops->name)
return -EINVAL;
mutex_lock(&rate_ctrl_mutex);
list_for_each_entry(alg, &rate_ctrl_algs, list) {
if (!strcmp(alg->ops->name, ops->name)) {
/* don't register an algorithm twice */
WARN_ON(1);
mutex_unlock(&rate_ctrl_mutex);
return -EALREADY;
}
}
alg = kzalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL) {
mutex_unlock(&rate_ctrl_mutex);
return -ENOMEM;
}
alg->ops = ops;
mutex_lock(&rate_ctrl_mutex);
list_add_tail(&alg->list, &rate_ctrl_algs);
mutex_unlock(&rate_ctrl_mutex);
@ -47,11 +65,11 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
list_for_each_entry(alg, &rate_ctrl_algs, list) {
if (alg->ops == ops) {
list_del(&alg->list);
kfree(alg);
break;
}
}
mutex_unlock(&rate_ctrl_mutex);
kfree(alg);
}
EXPORT_SYMBOL(ieee80211_rate_control_unregister);
@ -61,9 +79,12 @@ ieee80211_try_rate_control_ops_get(const char *name)
struct rate_control_alg *alg;
struct rate_control_ops *ops = NULL;
if (!name)
return NULL;
mutex_lock(&rate_ctrl_mutex);
list_for_each_entry(alg, &rate_ctrl_algs, list) {
if (!name || !strcmp(alg->ops->name, name))
if (!strcmp(alg->ops->name, name))
if (try_module_get(alg->ops->module)) {
ops = alg->ops;
break;
@ -73,18 +94,31 @@ ieee80211_try_rate_control_ops_get(const char *name)
return ops;
}
/* Get the rate control algorithm. If `name' is NULL, get the first
* available algorithm. */
/* Get the rate control algorithm. */
static struct rate_control_ops *
ieee80211_rate_control_ops_get(const char *name)
{
struct rate_control_ops *ops;
const char *alg_name;
ops = ieee80211_try_rate_control_ops_get(name);
if (!name)
alg_name = ieee80211_default_rc_algo;
else
alg_name = name;
ops = ieee80211_try_rate_control_ops_get(alg_name);
if (!ops) {
request_module("rc80211_%s", name ? name : "default");
ops = ieee80211_try_rate_control_ops_get(name);
request_module("rc80211_%s", alg_name);
ops = ieee80211_try_rate_control_ops_get(alg_name);
}
if (!ops && name)
/* try default if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
/* try built-in one if specific alg requested but not found */
if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
return ops;
}
@ -128,6 +162,38 @@ static void rate_control_release(struct kref *kref)
kfree(ctrl_ref);
}
void rate_control_get_rate(struct net_device *dev,
struct ieee80211_supported_band *sband,
struct sk_buff *skb,
struct rate_selection *sel)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct sta_info *sta = sta_info_get(local, hdr->addr1);
int i;
memset(sel, 0, sizeof(struct rate_selection));
ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
/* Select a non-ERP backup rate. */
if (!sel->nonerp) {
for (i = 0; i < sband->n_bitrates; i++) {
struct ieee80211_rate *rate = &sband->bitrates[i];
if (sel->rate->bitrate < rate->bitrate)
break;
if (rate_supported(sta, sband->band, i) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
sel->nonerp = rate;
}
}
if (sta)
sta_info_put(sta);
}
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
{
kref_get(&ref->kref);
@ -178,3 +244,4 @@ void rate_control_deinitialize(struct ieee80211_local *local)
local->rate_ctrl = NULL;
rate_control_put(ref);
}

View File

@ -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,
void (*get_rate)(void *priv, struct net_device *dev,
struct ieee80211_supported_band *band,
struct sk_buff *skb,
struct rate_control_extra *extra);
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,28 +67,24 @@ 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);
}
static inline void rate_control_rate_init(struct sta_info *sta,
struct ieee80211_local *local)
{
@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -49,8 +49,8 @@ static const u8 *get_mac_for_key(struct ieee80211_key *key)
* address to indicate a transmit-only key.
*/
if (key->conf.alg != ALG_WEP &&
(key->sdata->type == IEEE80211_IF_TYPE_AP ||
key->sdata->type == IEEE80211_IF_TYPE_VLAN))
(key->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN))
addr = zero_addr;
if (key->sta)
@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{
const u8 *addr;
int ret;
DECLARE_MAC_BUF(mac);
if (!key->local->ops->set_key)
return;
@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
printk(KERN_ERR "mac80211-%s: failed to set key "
"(%d, " MAC_FMT ") to hardware (%d)\n",
"(%d, %s) to hardware (%d)\n",
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, MAC_ARG(addr), ret);
key->conf.keyidx, print_mac(mac, addr), ret);
}
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
{
const u8 *addr;
int ret;
DECLARE_MAC_BUF(mac);
if (!key->local->ops->set_key)
return;
@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
if (ret)
printk(KERN_ERR "mac80211-%s: failed to remove key "
"(%d, " MAC_FMT ") from hardware (%d)\n",
"(%d, %s) from hardware (%d)\n",
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, MAC_ARG(addr), ret);
key->conf.keyidx, print_mac(mac, addr), ret);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
}
@ -170,7 +172,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
if (sta->flags & WLAN_STA_WME)
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
} else {
if (sdata->type == IEEE80211_IF_TYPE_STA) {
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct sta_info *ap;
/* same here, the AP could be using QoS */

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -7,13 +7,13 @@
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/compiler.h>
#include <linux/module.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
@ -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));
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);
}
sta = sta_info_get(local, hdr->addr1);
if (!sta)
return rate_control_lowest_rate(local, mode);
/* 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 = 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
};
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");
MODULE_DESCRIPTION("Simple rate control algorithm");
int __init rc80211_simple_init(void)
{
return ieee80211_rate_control_register(&mac80211_rcsimple);
}
void rc80211_simple_exit(void)
{
ieee80211_rate_control_unregister(&mac80211_rcsimple);
}
#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE
module_init(rc80211_simple_init);
module_exit(rc80211_simple_exit);
#endif

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/timer.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
@ -73,36 +74,13 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
}
EXPORT_SYMBOL(sta_info_get);
int sta_info_min_txrate_get(struct ieee80211_local *local)
{
struct sta_info *sta;
struct ieee80211_hw_mode *mode;
int min_txrate = 9999999;
int i;
read_lock_bh(&local->sta_lock);
mode = local->oper_hw_mode;
for (i = 0; i < STA_HASH_SIZE; i++) {
sta = local->sta_hash[i];
while (sta) {
if (sta->txrate < min_txrate)
min_txrate = sta->txrate;
sta = sta->hnext;
}
}
read_unlock_bh(&local->sta_lock);
if (min_txrate == 9999999)
min_txrate = 0;
return mode->rates[min_txrate].rate;
}
static void sta_info_release(struct kref *kref)
{
struct sta_info *sta = container_of(kref, struct sta_info, kref);
struct ieee80211_local *local = sta->local;
struct sk_buff *skb;
int i;
/* free sta structure; it has already been removed from
* hash table etc. external structures. Make sure that all
@ -115,6 +93,10 @@ static void sta_info_release(struct kref *kref)
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
dev_kfree_skb_any(skb);
}
for (i = 0; i < STA_TID_NUM; i++) {
del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
}
rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
rate_control_put(sta->rate_ctrl);
kfree(sta);
@ -132,6 +114,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
struct net_device *dev, u8 *addr, gfp_t gfp)
{
struct sta_info *sta;
int i;
DECLARE_MAC_BUF(mac);
sta = kzalloc(sizeof(*sta), gfp);
if (!sta)
@ -150,6 +134,28 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
memcpy(sta->addr, addr, ETH_ALEN);
sta->local = local;
sta->dev = dev;
spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to
* sta_rx_agg_session_timer_expired for useage */
sta->timer_to_tid[i] = i;
/* tid to tx queue: initialize according to HW (0 is valid) */
sta->tid_to_tx_q[i] = local->hw.queues;
/* rx timers */
sta->ampdu_mlme.tid_rx[i].session_timer.function =
sta_rx_agg_session_timer_expired;
sta->ampdu_mlme.tid_rx[i].session_timer.data =
(unsigned long)&sta->timer_to_tid[i];
init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
/* tx timers */
sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
sta_addba_resp_timer_expired;
sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
(unsigned long)&sta->timer_to_tid[i];
init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
}
skb_queue_head_init(&sta->ps_tx_buf);
skb_queue_head_init(&sta->tx_filtered);
__sta_info_get(sta); /* sta used by caller, decremented by
@ -158,14 +164,21 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
list_add(&sta->list, &local->sta_list);
local->num_sta++;
sta_info_hash_add(local, sta);
if (local->ops->sta_notify)
local->ops->sta_notify(local_to_hw(local), dev->ifindex,
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,
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;

View File

@ -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
/**
* 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.
*/
#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 {
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);

View File

@ -276,9 +276,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
(iv32 == key->u.tkip.iv32_rx[queue] &&
iv16 <= key->u.tkip.iv16_rx[queue]))) {
#ifdef CONFIG_TKIP_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "TKIP replay detected for RX frame from "
MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
MAC_ARG(ta),
"%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
print_mac(mac, ta),
iv32, iv16, key->u.tkip.iv32_rx[queue],
key->u.tkip.iv16_rx[queue]);
#endif /* CONFIG_TKIP_DEBUG */
@ -300,8 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
#ifdef CONFIG_TKIP_DEBUG
{
int i;
printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT
" TK=", MAC_ARG(ta));
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
" TK=", print_mac(mac, ta));
for (i = 0; i < 16; i++)
printk("%02x ",
key->conf.key[

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,9 @@
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/bitmap.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
@ -38,108 +40,22 @@ const unsigned char rfc1042_header[] =
const unsigned char bridge_tunnel_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
/* No encapsulation header if EtherType < 0x600 (=length) */
static const unsigned char eapol_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
static int rate_list_match(const int *rate_list, int rate)
{
int i;
if (!rate_list)
return 0;
for (i = 0; rate_list[i] >= 0; i++)
if (rate_list[i] == rate)
return 1;
return 0;
}
void ieee80211_prepare_rates(struct ieee80211_local *local,
struct ieee80211_hw_mode *mode)
{
int i;
for (i = 0; i < mode->num_rates; i++) {
struct ieee80211_rate *rate = &mode->rates[i];
rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
IEEE80211_RATE_BASIC);
if (local->supp_rates[mode->mode]) {
if (!rate_list_match(local->supp_rates[mode->mode],
rate->rate))
continue;
}
rate->flags |= IEEE80211_RATE_SUPPORTED;
/* Use configured basic rate set if it is available. If not,
* use defaults that are sane for most cases. */
if (local->basic_rates[mode->mode]) {
if (rate_list_match(local->basic_rates[mode->mode],
rate->rate))
rate->flags |= IEEE80211_RATE_BASIC;
} else switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
rate->flags |= IEEE80211_RATE_BASIC;
break;
case MODE_IEEE80211B:
if (rate->rate == 10 || rate->rate == 20)
rate->flags |= IEEE80211_RATE_BASIC;
break;
case MODE_IEEE80211G:
if (rate->rate == 10 || rate->rate == 20 ||
rate->rate == 55 || rate->rate == 110)
rate->flags |= IEEE80211_RATE_BASIC;
break;
case NUM_IEEE80211_MODES:
/* not useful */
break;
}
/* Set ERP and MANDATORY flags based on phymode */
switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
rate->flags |= IEEE80211_RATE_MANDATORY;
break;
case MODE_IEEE80211B:
if (rate->rate == 10)
rate->flags |= IEEE80211_RATE_MANDATORY;
break;
case MODE_IEEE80211G:
if (rate->rate == 10 || rate->rate == 20 ||
rate->rate == 55 || rate->rate == 110 ||
rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
rate->flags |= IEEE80211_RATE_MANDATORY;
break;
case NUM_IEEE80211_MODES:
/* not useful */
break;
}
if (ieee80211_is_erp_rate(mode->mode, rate->rate))
rate->flags |= IEEE80211_RATE_ERP;
}
}
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum ieee80211_if_types type)
{
u16 fc;
if (len < 24)
/* drop ACK/CTS frames and incorrect hdr len (ctrl) */
if (len < 16)
return NULL;
fc = le16_to_cpu(hdr->frame_control);
switch (fc & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_DATA:
if (len < 24) /* drop incorrect hdr len (data) */
return NULL;
switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
case IEEE80211_FCTL_TODS:
return hdr->addr1;
@ -152,10 +68,24 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
}
break;
case IEEE80211_FTYPE_MGMT:
if (len < 24) /* drop incorrect hdr len (mgmt) */
return NULL;
return hdr->addr3;
case IEEE80211_FTYPE_CTL:
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
return hdr->addr1;
else if ((fc & IEEE80211_FCTL_STYPE) ==
IEEE80211_STYPE_BACK_REQ) {
switch (type) {
case IEEE80211_IF_TYPE_STA:
return hdr->addr2;
case IEEE80211_IF_TYPE_AP:
case IEEE80211_IF_TYPE_VLAN:
return hdr->addr1;
default:
return NULL;
}
}
else
return NULL;
}
@ -216,31 +146,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
int ieee80211_is_eapol(const struct sk_buff *skb)
{
const struct ieee80211_hdr *hdr;
u16 fc;
int hdrlen;
if (unlikely(skb->len < 10))
return 0;
hdr = (const struct ieee80211_hdr *) skb->data;
fc = le16_to_cpu(hdr->frame_control);
if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
return 0;
hdrlen = ieee80211_get_hdrlen(fc);
if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
memcmp(skb->data + hdrlen, eapol_header,
sizeof(eapol_header)) == 0))
return 1;
return 0;
}
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
@ -271,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
* DIV_ROUND_UP() operations.
*/
if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
/*
* OFDM:
*
@ -311,120 +216,92 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
}
/* Exported duration function for driver use */
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
size_t frame_len, int rate)
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
struct net_device *bdev = dev_get_by_index(if_id);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
u16 dur;
int erp;
if (unlikely(!bdev))
return 0;
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
erp = rate->flags & IEEE80211_RATE_ERP_G;
sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
dur = ieee80211_frame_duration(local, frame_len, rate,
erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
sdata->bss_conf.use_short_preamble);
dev_put(bdev);
return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_generic_frame_duration);
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
size_t frame_len,
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, size_t frame_len,
const struct ieee80211_tx_control *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
struct net_device *bdev = dev_get_by_index(if_id);
struct ieee80211_sub_if_data *sdata;
int short_preamble;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
bool short_preamble;
int erp;
u16 dur;
if (unlikely(!bdev))
return 0;
short_preamble = sdata->bss_conf.use_short_preamble;
sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
rate = frame_txctl->rts_cts_rate;
rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
erp = rate->flags & IEEE80211_RATE_ERP_G;
/* CTS duration */
dur = ieee80211_frame_duration(local, 10, rate->rate,
dur = ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
/* Data frame duration */
dur += ieee80211_frame_duration(local, frame_len, rate->rate,
dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
/* ACK duration */
dur += ieee80211_frame_duration(local, 10, rate->rate,
dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
dev_put(bdev);
return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_rts_duration);
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
const struct ieee80211_tx_control *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
struct net_device *bdev = dev_get_by_index(if_id);
struct ieee80211_sub_if_data *sdata;
int short_preamble;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
bool short_preamble;
int erp;
u16 dur;
if (unlikely(!bdev))
return 0;
short_preamble = sdata->bss_conf.use_short_preamble;
sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
rate = frame_txctl->rts_cts_rate;
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
erp = rate->flags & IEEE80211_RATE_ERP_G;
/* Data frame duration */
dur = ieee80211_frame_duration(local, frame_len, rate->rate,
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
/* ACK duration */
dur += ieee80211_frame_duration(local, 10, rate->rate,
dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
}
dev_put(bdev);
return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
struct ieee80211_rate *
ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
{
struct ieee80211_hw_mode *mode;
int r;
list_for_each_entry(mode, &local->modes_list, list) {
if (mode->mode != phymode)
continue;
for (r = 0; r < mode->num_rates; r++) {
struct ieee80211_rate *rate = &mode->rates[r];
if (rate->val == hw_rate ||
(rate->flags & IEEE80211_RATE_PREAMBLE2 &&
rate->val2 == hw_rate))
return rate;
}
}
return NULL;
}
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
@ -483,3 +360,37 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
ieee80211_wake_queue(hw, i);
}
EXPORT_SYMBOL(ieee80211_wake_queues);
void ieee80211_iterate_active_interfaces(
struct ieee80211_hw *hw,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_INVALID:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_VLAN:
continue;
case IEEE80211_IF_TYPE_AP:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
case IEEE80211_IF_TYPE_WDS:
break;
}
if (sdata->dev == local->mdev)
continue;
if (netif_running(sdata->dev))
iterator(data, sdata->dev->dev_addr,
&sdata->vif);
}
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);

View File

@ -16,7 +16,7 @@
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/mm.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
crypto_blkcipher_setkey(tfm, rc4key, klen);
sg.page = virt_to_page(data);
sg.offset = offset_in_page(data);
sg.length = data_len + WEP_ICV_LEN;
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
}
@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
__le32 crc;
crypto_blkcipher_setkey(tfm, rc4key, klen);
sg.page = virt_to_page(data);
sg.offset = offset_in_page(data);
sg.length = data_len + WEP_ICV_LEN;
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
crc = cpu_to_le32(~crc32_le(~0, data, data_len));
@ -269,6 +265,7 @@ 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)) {
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;
}

View File

@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_key *key);
u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
ieee80211_txrx_result
ieee80211_rx_result
ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
ieee80211_txrx_result
ieee80211_tx_result
ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
#endif /* WEP_H */

View File

@ -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);
}
}

View File

@ -24,6 +24,8 @@
#define QOS_CONTROL_TAG1D_MASK 0x07
extern const int ieee802_1d_to_ac[8];
static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
{
return (fc & 0x8C) == 0x88;
@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
#ifdef CONFIG_NET_SCHED
void ieee80211_install_qdisc(struct net_device *dev);
int ieee80211_qdisc_installed(struct net_device *dev);
int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
struct sta_info *sta, u16 tid);
void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
struct sta_info *sta, u16 tid,
u8 requeue);
void ieee80211_requeue(struct ieee80211_local *local, int queue);
int ieee80211_wme_register(void);
void ieee80211_wme_unregister(void);
#else
@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev)
{
return 0;
}
static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
return -EAGAIN;
}
static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
struct sta_info *sta, u16 tid,
u8 requeue)
{
}
static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
{
}
static inline int ieee80211_wme_register(void)
{
return 0;

View File

@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
}
ieee80211_txrx_result
ieee80211_tx_result
ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
{
u8 *data, *sa, *da, *key, *mic, qos_tid;
@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
!WLAN_FC_DATA_PRESENT(fc))
return TXRX_CONTINUE;
return TX_CONTINUE;
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
return TXRX_DROP;
return TX_DROP;
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
!(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
!wpa_test) {
/* hwaccel - with no need for preallocated room for Michael MIC
*/
return TXRX_CONTINUE;
return TX_CONTINUE;
}
if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
GFP_ATOMIC))) {
printk(KERN_DEBUG "%s: failed to allocate more memory "
"for Michael MIC\n", tx->dev->name);
return TXRX_DROP;
return TX_DROP;
}
}
@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
mic = skb_put(skb, MICHAEL_MIC_LEN);
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
return TXRX_CONTINUE;
return TX_CONTINUE;
}
ieee80211_txrx_result
ieee80211_rx_result
ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
{
u8 *data, *sa, *da, *key = NULL, qos_tid;
@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
u8 mic[MICHAEL_MIC_LEN];
struct sk_buff *skb = rx->skb;
int authenticator = 1, wpa_test = 0;
DECLARE_MAC_BUF(mac);
fc = rx->fc;
@ -139,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
* No way to verify the MIC if the hardware stripped it
*/
if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
return TXRX_CONTINUE;
return RX_CONTINUE;
if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
!(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
return TXRX_CONTINUE;
return RX_CONTINUE;
if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
|| data_len < MICHAEL_MIC_LEN)
return TXRX_DROP;
return RX_DROP_UNUSABLE;
data_len -= MICHAEL_MIC_LEN;
@ -161,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
return TXRX_DROP;
return RX_DROP_UNUSABLE;
printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
"%s\n", rx->dev->name, print_mac(mac, sa));
mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
(void *) skb->data);
return TXRX_DROP;
return RX_DROP_UNUSABLE;
}
/* remove Michael MIC from payload */
@ -178,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32;
rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16;
return TXRX_CONTINUE;
return RX_CONTINUE;
}
@ -241,19 +242,12 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
}
ieee80211_txrx_result
ieee80211_tx_result
ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 fc;
struct sk_buff *skb = tx->skb;
int wpa_test = 0, test = 0;
fc = le16_to_cpu(hdr->frame_control);
if (!WLAN_FC_DATA_PRESENT(fc))
return TXRX_CONTINUE;
tx->u.tx.control->icv_len = TKIP_ICV_LEN;
tx->u.tx.control->iv_len = TKIP_IV_LEN;
ieee80211_tx_set_iswep(tx);
@ -263,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
!wpa_test) {
/* hwaccel - with no need for preallocated room for IV/ICV */
tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
return TXRX_CONTINUE;
return TX_CONTINUE;
}
if (tkip_encrypt_skb(tx, skb, test) < 0)
return TXRX_DROP;
return TX_DROP;
if (tx->u.tx.extra_frag) {
int i;
for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
< 0)
return TXRX_DROP;
return TX_DROP;
}
}
return TXRX_CONTINUE;
return TX_CONTINUE;
}
ieee80211_txrx_result
ieee80211_rx_result
ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@ -290,15 +284,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
int hdrlen, res, hwaccel = 0, wpa_test = 0;
struct ieee80211_key *key = rx->key;
struct sk_buff *skb = rx->skb;
DECLARE_MAC_BUF(mac);
fc = le16_to_cpu(hdr->frame_control);
hdrlen = ieee80211_get_hdrlen(fc);
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
return TXRX_CONTINUE;
return RX_CONTINUE;
if (!rx->sta || skb->len - hdrlen < 12)
return TXRX_DROP;
return RX_DROP_UNUSABLE;
if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
@ -307,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
* replay protection, and stripped the ICV/IV so
* we cannot do any checks here.
*/
return TXRX_CONTINUE;
return RX_CONTINUE;
}
/* let TKIP code verify IV, but skip decryption */
@ -321,10 +316,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
&rx->u.rx.tkip_iv32,
&rx->u.rx.tkip_iv16);
if (res != TKIP_DECRYPT_OK || wpa_test) {
printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from "
MAC_FMT " (res=%d)\n",
rx->dev->name, MAC_ARG(rx->sta->addr), res);
return TXRX_DROP;
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: TKIP decrypt failed for RX "
"frame from %s (res=%d)\n", rx->dev->name,
print_mac(mac, rx->sta->addr), res);
#endif /* CONFIG_MAC80211_DEBUG */
return RX_DROP_UNUSABLE;
}
/* Trim ICV */
@ -334,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
skb_pull(skb, TKIP_IV_LEN);
return TXRX_CONTINUE;
return RX_CONTINUE;
}
@ -493,19 +491,12 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
}
ieee80211_txrx_result
ieee80211_tx_result
ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 fc;
struct sk_buff *skb = tx->skb;
int test = 0;
fc = le16_to_cpu(hdr->frame_control);
if (!WLAN_FC_DATA_PRESENT(fc))
return TXRX_CONTINUE;
tx->u.tx.control->icv_len = CCMP_MIC_LEN;
tx->u.tx.control->iv_len = CCMP_HDR_LEN;
ieee80211_tx_set_iswep(tx);
@ -515,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
/* hwaccel - with no need for preallocated room for CCMP "
* header or MIC fields */
tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
return TXRX_CONTINUE;
return TX_CONTINUE;
}
if (ccmp_encrypt_skb(tx, skb, test) < 0)
return TXRX_DROP;
return TX_DROP;
if (tx->u.tx.extra_frag) {
int i;
for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
< 0)
return TXRX_DROP;
return TX_DROP;
}
}
return TXRX_CONTINUE;
return TX_CONTINUE;
}
ieee80211_txrx_result
ieee80211_rx_result
ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@ -544,35 +535,37 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
struct sk_buff *skb = rx->skb;
u8 pn[CCMP_PN_LEN];
int data_len;
DECLARE_MAC_BUF(mac);
fc = le16_to_cpu(hdr->frame_control);
hdrlen = ieee80211_get_hdrlen(fc);
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
return TXRX_CONTINUE;
return RX_CONTINUE;
data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
if (!rx->sta || data_len < 0)
return TXRX_DROP;
return RX_DROP_UNUSABLE;
if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
return TXRX_CONTINUE;
return RX_CONTINUE;
(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
#ifdef CONFIG_MAC80211_DEBUG
u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
"%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
"%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
MAC_ARG(rx->sta->addr),
print_mac(mac, rx->sta->addr),
pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
#endif /* CONFIG_MAC80211_DEBUG */
key->u.ccmp.replays++;
return TXRX_DROP;
return RX_DROP_UNUSABLE;
}
if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
@ -590,10 +583,13 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
skb->data + hdrlen + CCMP_HDR_LEN, data_len,
skb->data + skb->len - CCMP_MIC_LEN,
skb->data + hdrlen + CCMP_HDR_LEN)) {
printk(KERN_DEBUG "%s: CCMP decrypt failed for RX "
"frame from " MAC_FMT "\n", rx->dev->name,
MAC_ARG(rx->sta->addr));
return TXRX_DROP;
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: CCMP decrypt failed "
"for RX frame from %s\n", rx->dev->name,
print_mac(mac, rx->sta->addr));
#endif /* CONFIG_MAC80211_DEBUG */
return RX_DROP_UNUSABLE;
}
}
@ -604,6 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
skb_pull(skb, CCMP_HDR_LEN);
return TXRX_CONTINUE;
return RX_CONTINUE;
}

View File

@ -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 */

View File

@ -3,7 +3,7 @@ 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

View File

@ -1,4 +1,5 @@
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
cfg80211-y += core.o sysfs.o radiotap.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
cfg80211-$(CONFIG_NL80211) += nl80211.o

View File

@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_info *info)
if (info->attrs[NL80211_ATTR_IFINDEX]) {
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
dev = dev_get_by_index(ifindex);
dev = dev_get_by_index(&init_net, ifindex);
if (dev) {
if (dev->ieee80211_ptr)
byifidx =
@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
struct net_device *dev;
mutex_lock(&cfg80211_drv_mutex);
dev = dev_get_by_index(ifindex);
dev = dev_get_by_index(&init_net, ifindex);
if (!dev)
goto out;
if (dev->ieee80211_ptr) {
@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
struct cfg80211_registered_device *drv;
int alloc_size;
WARN_ON(!ops->add_key && ops->del_key);
WARN_ON(ops->add_key && !ops->del_key);
alloc_size = sizeof(*drv) + sizeof_priv;
drv = kzalloc(alloc_size, GFP_KERNEL);
@ -229,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy)
{
struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
int res;
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
bool have_band = false;
int i;
/* sanity check supported bands/channels */
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
sband = wiphy->bands[band];
if (!sband)
continue;
sband->band = band;
if (!sband->n_channels || !sband->n_bitrates) {
WARN_ON(1);
return -EINVAL;
}
for (i = 0; i < sband->n_channels; i++) {
sband->channels[i].orig_flags =
sband->channels[i].flags;
sband->channels[i].orig_mag =
sband->channels[i].max_antenna_gain;
sband->channels[i].orig_mpwr =
sband->channels[i].max_power;
sband->channels[i].band = band;
}
have_band = true;
}
if (!have_band) {
WARN_ON(1);
return -EINVAL;
}
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
/* set up regulatory info */
wiphy_update_regulatory(wiphy);
mutex_lock(&cfg80211_drv_mutex);

View File

@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
char *newname);
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
void wiphy_update_regulatory(struct wiphy *wiphy);
#endif /* __NET_WIRELESS_CORE_H */

View File

@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
return -EINVAL;
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
*dev = dev_get_by_index(ifindex);
*dev = dev_get_by_index(&init_net, ifindex);
if (!*dev)
return -ENODEV;
@ -61,6 +61,28 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
[NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
[NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
};
/* message building helper */
@ -77,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *dev)
{
void *hdr;
struct nlattr *nl_bands, *nl_band;
struct nlattr *nl_freqs, *nl_freq;
struct nlattr *nl_rates, *nl_rate;
enum ieee80211_band band;
struct ieee80211_channel *chan;
struct ieee80211_rate *rate;
int i;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
if (!hdr)
@ -84,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
if (!nl_bands)
goto nla_put_failure;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!dev->wiphy.bands[band])
continue;
nl_band = nla_nest_start(msg, band);
if (!nl_band)
goto nla_put_failure;
/* add frequencies */
nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
if (!nl_freqs)
goto nla_put_failure;
for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
nl_freq = nla_nest_start(msg, i);
if (!nl_freq)
goto nla_put_failure;
chan = &dev->wiphy.bands[band]->channels[i];
NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
chan->center_freq);
if (chan->flags & IEEE80211_CHAN_DISABLED)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
if (chan->flags & IEEE80211_CHAN_NO_IBSS)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
if (chan->flags & IEEE80211_CHAN_RADAR)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
nla_nest_end(msg, nl_freq);
}
nla_nest_end(msg, nl_freqs);
/* add bitrates */
nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
if (!nl_rates)
goto nla_put_failure;
for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
nl_rate = nla_nest_start(msg, i);
if (!nl_rate)
goto nla_put_failure;
rate = &dev->wiphy.bands[band]->bitrates[i];
NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
rate->bitrate);
if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
NLA_PUT_FLAG(msg,
NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
nla_nest_end(msg, nl_rate);
}
nla_nest_end(msg, nl_rates);
nla_nest_end(msg, nl_band);
}
nla_nest_end(msg, nl_bands);
return genlmsg_end(msg, hdr);
nla_put_failure:
@ -241,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
return -ENOBUFS;
}
static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
[NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
};
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
{
struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
int flag;
*mntrflags = 0;
if (!nla)
return -EINVAL;
if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
nla, mntr_flags_policy))
return -EINVAL;
for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
if (flags[flag])
*mntrflags |= (1<<flag);
return 0;
}
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err, ifindex;
enum nl80211_iftype type;
struct net_device *dev;
u32 flags;
if (info->attrs[NL80211_ATTR_IFTYPE]) {
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@ -267,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
rtnl_lock();
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
type, err ? NULL : &flags);
rtnl_unlock();
unlock:
@ -280,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *drv;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
u32 flags;
if (!info->attrs[NL80211_ATTR_IFNAME])
return -EINVAL;
@ -300,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
}
rtnl_lock();
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
err = drv->ops->add_virtual_intf(&drv->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags);
rtnl_unlock();
unlock:
@ -335,6 +470,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
return err;
}
struct get_key_cookie {
struct sk_buff *msg;
int error;
};
static void get_key_callback(void *c, struct key_params *params)
{
struct get_key_cookie *cookie = c;
if (params->key)
NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
params->key_len, params->key);
if (params->seq)
NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
params->seq_len, params->seq);
if (params->cipher)
NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
params->cipher);
return;
nla_put_failure:
cookie->error = 1;
}
static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
u8 key_idx = 0;
u8 *mac_addr = NULL;
struct get_key_cookie cookie = {
.error = 0,
};
void *hdr;
struct sk_buff *msg;
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
if (key_idx > 3)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->get_key) {
err = -EOPNOTSUPP;
goto out;
}
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg) {
err = -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_NEW_KEY);
if (IS_ERR(hdr)) {
err = PTR_ERR(hdr);
goto out;
}
cookie.msg = msg;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
if (mac_addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
rtnl_lock();
err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
&cookie, get_key_callback);
rtnl_unlock();
if (err)
goto out;
if (cookie.error)
goto nla_put_failure;
genlmsg_end(msg, hdr);
err = genlmsg_unicast(msg, info->snd_pid);
goto out;
nla_put_failure:
err = -ENOBUFS;
nlmsg_free(msg);
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
u8 key_idx;
if (!info->attrs[NL80211_ATTR_KEY_IDX])
return -EINVAL;
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
if (key_idx > 3)
return -EINVAL;
/* currently only support setting default key */
if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->set_default_key) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct key_params params;
u8 key_idx = 0;
u8 *mac_addr = NULL;
memset(&params, 0, sizeof(params));
if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
return -EINVAL;
if (info->attrs[NL80211_ATTR_KEY_DATA]) {
params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
}
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (key_idx > 3)
return -EINVAL;
/*
* Disallow pairwise keys with non-zero index unless it's WEP
* (because current deployments use pairwise WEP keys with
* non-zero indizes but 802.11i clearly specifies to use zero)
*/
if (mac_addr && key_idx &&
params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
params.cipher != WLAN_CIPHER_SUITE_WEP104)
return -EINVAL;
/* TODO: add definitions for the lengths to linux/ieee80211.h */
switch (params.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
if (params.key_len != 5)
return -EINVAL;
break;
case WLAN_CIPHER_SUITE_TKIP:
if (params.key_len != 32)
return -EINVAL;
break;
case WLAN_CIPHER_SUITE_CCMP:
if (params.key_len != 16)
return -EINVAL;
break;
case WLAN_CIPHER_SUITE_WEP104:
if (params.key_len != 13)
return -EINVAL;
break;
default:
return -EINVAL;
}
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->add_key) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
u8 key_idx = 0;
u8 *mac_addr = NULL;
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
if (key_idx > 3)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->del_key) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
{
int (*call)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct beacon_parameters params;
int haveinfo = 0;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
switch (info->genlhdr->cmd) {
case NL80211_CMD_NEW_BEACON:
/* these are required for NEW_BEACON */
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
!info->attrs[NL80211_ATTR_BEACON_HEAD]) {
err = -EINVAL;
goto out;
}
call = drv->ops->add_beacon;
break;
case NL80211_CMD_SET_BEACON:
call = drv->ops->set_beacon;
break;
default:
WARN_ON(1);
err = -EOPNOTSUPP;
goto out;
}
if (!call) {
err = -EOPNOTSUPP;
goto out;
}
memset(&params, 0, sizeof(params));
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
params.interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
haveinfo = 1;
}
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
haveinfo = 1;
}
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
params.head_len =
nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
haveinfo = 1;
}
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
params.tail_len =
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
haveinfo = 1;
}
if (!haveinfo) {
err = -EINVAL;
goto out;
}
rtnl_lock();
err = call(&drv->wiphy, dev, &params);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->del_beacon) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->del_beacon(&drv->wiphy, dev);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
};
static int parse_station_flags(struct nlattr *nla, u32 *staflags)
{
struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
int flag;
*staflags = 0;
if (!nla)
return 0;
if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
nla, sta_flags_policy))
return -EINVAL;
*staflags = STATION_FLAG_CHANGED;
for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
if (flags[flag])
*staflags |= (1<<flag);
return 0;
}
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
int flags, struct net_device *dev,
u8 *mac_addr, struct station_stats *stats)
{
void *hdr;
struct nlattr *statsattr;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
if (!hdr)
return -1;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
if (!statsattr)
goto nla_put_failure;
if (stats->filled & STATION_STAT_INACTIVE_TIME)
NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
stats->inactive_time);
if (stats->filled & STATION_STAT_RX_BYTES)
NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
stats->rx_bytes);
if (stats->filled & STATION_STAT_TX_BYTES)
NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
stats->tx_bytes);
nla_nest_end(msg, statsattr);
return genlmsg_end(msg, hdr);
nla_put_failure:
return genlmsg_cancel(msg, hdr);
}
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct station_stats stats;
struct sk_buff *msg;
u8 *mac_addr = NULL;
memset(&stats, 0, sizeof(stats));
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->get_station) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
rtnl_unlock();
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
goto out;
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
dev, mac_addr, &stats) < 0)
goto out_free;
err = genlmsg_unicast(msg, info->snd_pid);
goto out;
out_free:
nlmsg_free(msg);
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
/*
* Get vlan interface making sure it is on the right wiphy.
*/
static int get_vlan(struct nlattr *vlanattr,
struct cfg80211_registered_device *rdev,
struct net_device **vlan)
{
*vlan = NULL;
if (vlanattr) {
*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
if (!*vlan)
return -ENODEV;
if (!(*vlan)->ieee80211_ptr)
return -EINVAL;
if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
return -EINVAL;
}
return 0;
}
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct station_parameters params;
u8 *mac_addr = NULL;
memset(&params, 0, sizeof(params));
params.listen_interval = -1;
if (info->attrs[NL80211_ATTR_STA_AID])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
params.supported_rates =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
params.supported_rates_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
}
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
&params.station_flags))
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err)
goto out;
if (!drv->ops->change_station) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
rtnl_unlock();
out:
if (params.vlan)
dev_put(params.vlan);
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
struct station_parameters params;
u8 *mac_addr = NULL;
memset(&params, 0, sizeof(params));
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_STA_AID])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
return -EINVAL;
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
params.supported_rates =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
params.supported_rates_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
&params.station_flags))
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err)
goto out;
if (!drv->ops->add_station) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
rtnl_unlock();
out:
if (params.vlan)
dev_put(params.vlan);
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
u8 *mac_addr = NULL;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
if (!drv->ops->del_station) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
dev_put(dev);
return err;
}
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@ -374,6 +1158,73 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_GET_KEY,
.doit = nl80211_get_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_SET_KEY,
.doit = nl80211_set_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_NEW_KEY,
.doit = nl80211_new_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_DEL_KEY,
.doit = nl80211_del_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon,
},
{
.cmd = NL80211_CMD_NEW_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon,
},
{
.cmd = NL80211_CMD_DEL_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_del_beacon,
},
{
.cmd = NL80211_CMD_GET_STATION,
.doit = nl80211_get_station,
/* TODO: implement dumpit */
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_SET_STATION,
.doit = nl80211_set_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_NEW_STATION,
.doit = nl80211_new_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_DEL_STATION,
.doit = nl80211_del_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
/* multicast groups */

View File

@ -0,0 +1,153 @@
/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This regulatory domain control implementation is highly incomplete, it
* only exists for the purpose of not regressing mac80211.
*
* For now, drivers can restrict the set of allowed channels by either
* not registering those channels or setting the IEEE80211_CHAN_DISABLED
* flag; that flag will only be *set* by this code, never *cleared.
*
* The usual implementation is for a driver to read a device EEPROM to
* determine which regulatory domain it should be operating under, then
* looking up the allowable channels in a driver-local table and finally
* registering those channels in the wiphy structure.
*
* Alternatively, drivers that trust the regulatory domain control here
* will register a complete set of capabilities and the control code
* will restrict the set by setting the IEEE80211_CHAN_* flags.
*/
#include <linux/kernel.h>
#include <net/wireless.h>
#include "core.h"
static char *ieee80211_regdom = "US";
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
struct ieee80211_channel_range {
short start_freq;
short end_freq;
int max_power;
int max_antenna_gain;
u32 flags;
};
struct ieee80211_regdomain {
const char *code;
const struct ieee80211_channel_range *ranges;
int n_ranges;
};
#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \
{ _start, _end, _pwr, _ag, _flags }
/*
* Ideally, in the future, these definitions will be loaded from a
* userspace table via some daemon.
*/
static const struct ieee80211_channel_range ieee80211_US_channels[] = {
/* IEEE 802.11b/g, channels 1..11 */
RANGE_PWR(2412, 2462, 27, 6, 0),
/* IEEE 802.11a, channels 52..64 */
RANGE_PWR(5260, 5320, 23, 6, 0),
/* IEEE 802.11a, channels 149..165, outdoor */
RANGE_PWR(5745, 5825, 30, 6, 0),
};
static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
/* IEEE 802.11b/g, channels 1..14 */
RANGE_PWR(2412, 2484, 20, 6, 0),
/* IEEE 802.11a, channels 34..48 */
RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
/* IEEE 802.11a, channels 52..64 */
RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_RADAR),
};
#define REGDOM(_code) \
{ \
.code = __stringify(_code), \
.ranges = ieee80211_ ##_code## _channels, \
.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \
}
static const struct ieee80211_regdomain ieee80211_regdoms[] = {
REGDOM(US),
REGDOM(JP),
};
static const struct ieee80211_regdomain *get_regdom(void)
{
static const struct ieee80211_channel_range
ieee80211_world_channels[] = {
/* IEEE 802.11b/g, channels 1..11 */
RANGE_PWR(2412, 2462, 27, 6, 0),
};
static const struct ieee80211_regdomain regdom_world = REGDOM(world);
int i;
for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
return &ieee80211_regdoms[i];
return &regdom_world;
}
static void handle_channel(struct ieee80211_channel *chan,
const struct ieee80211_regdomain *rd)
{
int i;
u32 flags = chan->orig_flags;
const struct ieee80211_channel_range *rg = NULL;
for (i = 0; i < rd->n_ranges; i++) {
if (rd->ranges[i].start_freq <= chan->center_freq &&
chan->center_freq <= rd->ranges[i].end_freq) {
rg = &rd->ranges[i];
break;
}
}
if (!rg) {
/* not found */
flags |= IEEE80211_CHAN_DISABLED;
chan->flags = flags;
return;
}
chan->flags = flags;
chan->max_antenna_gain = min(chan->orig_mag,
rg->max_antenna_gain);
chan->max_power = min(chan->orig_mpwr, rg->max_power);
}
static void handle_band(struct ieee80211_supported_band *sband,
const struct ieee80211_regdomain *rd)
{
int i;
for (i = 0; i < sband->n_channels; i++)
handle_channel(&sband->channels[i], rd);
}
void wiphy_update_regulatory(struct wiphy *wiphy)
{
enum ieee80211_band band;
const struct ieee80211_regdomain *rd = get_regdom();
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
if (wiphy->bands[band])
handle_band(wiphy->bands[band], rd);
}

Some files were not shown because too many files have changed in this diff Show More