mirror of https://github.com/hak5/openwrt.git
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: 10466lede-17.01
parent
4e45a1d1ac
commit
99aaf500ed
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
#define B43_MMIO_DMA4_IRQ_MASK 0x44
|
||||
#define B43_MMIO_DMA5_REASON 0x48
|
||||
#define B43_MMIO_DMA5_IRQ_MASK 0x4C
|
||||
#define B43_MMIO_MACCTL 0x120
|
||||
#define B43_MMIO_STATUS2_BITFIELD 0x124
|
||||
#define B43_MMIO_MACCTL 0x120 /* MAC control */
|
||||
#define B43_MMIO_MACCMD 0x124 /* MAC command */
|
||||
#define B43_MMIO_GEN_IRQ_REASON 0x128
|
||||
#define B43_MMIO_GEN_IRQ_MASK 0x12C
|
||||
#define B43_MMIO_RAM_CONTROL 0x130
|
||||
|
@ -50,6 +50,9 @@
|
|||
#define B43_MMIO_XMITSTAT_1 0x174
|
||||
#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
|
||||
#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
|
||||
#define B43_MMIO_TSF_CFP_REP 0x188
|
||||
#define B43_MMIO_TSF_CFP_START 0x18C
|
||||
#define B43_MMIO_TSF_CFP_MAXDUR 0x190
|
||||
|
||||
/* 32-bit DMA */
|
||||
#define B43_MMIO_DMA32_BASE0 0x200
|
||||
|
@ -65,11 +68,6 @@
|
|||
#define B43_MMIO_DMA64_BASE3 0x2C0
|
||||
#define B43_MMIO_DMA64_BASE4 0x300
|
||||
#define B43_MMIO_DMA64_BASE5 0x340
|
||||
/* PIO */
|
||||
#define B43_MMIO_PIO1_BASE 0x300
|
||||
#define B43_MMIO_PIO2_BASE 0x310
|
||||
#define B43_MMIO_PIO3_BASE 0x320
|
||||
#define B43_MMIO_PIO4_BASE 0x330
|
||||
|
||||
#define B43_MMIO_PHY_VER 0x3E0
|
||||
#define B43_MMIO_PHY_RADIO 0x3E2
|
||||
|
@ -88,6 +86,8 @@
|
|||
#define B43_MMIO_RADIO_HWENABLED_LO 0x49A
|
||||
#define B43_MMIO_GPIO_CONTROL 0x49C
|
||||
#define B43_MMIO_GPIO_MASK 0x49E
|
||||
#define B43_MMIO_TSF_CFP_START_LOW 0x604
|
||||
#define B43_MMIO_TSF_CFP_START_HIGH 0x606
|
||||
#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
|
||||
#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
|
||||
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
|
||||
|
@ -170,14 +170,17 @@ enum {
|
|||
#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */
|
||||
#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
|
||||
#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
|
||||
/* SHM_SHARED beacon variables */
|
||||
/* SHM_SHARED beacon/AP variables */
|
||||
#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
|
||||
#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
|
||||
#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
|
||||
#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
|
||||
#define B43_SHM_SH_DTIMP 0x0012 /* DTIP period */
|
||||
#define B43_SHM_SH_MCASTCOOKIE 0x00A8 /* Last bcast/mcast frame ID */
|
||||
#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */
|
||||
#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
|
||||
#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
|
||||
#define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */
|
||||
/* SHM_SHARED ACK/CTS control */
|
||||
#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
|
||||
/* SHM_SHARED probe response variables */
|
||||
|
@ -273,6 +276,8 @@ enum {
|
|||
#define B43_PHYTYPE_A 0x00
|
||||
#define B43_PHYTYPE_B 0x01
|
||||
#define B43_PHYTYPE_G 0x02
|
||||
#define B43_PHYTYPE_N 0x04
|
||||
#define B43_PHYTYPE_LP 0x05
|
||||
|
||||
/* PHYRegisters */
|
||||
#define B43_PHY_ILT_A_CTRL 0x0072
|
||||
|
@ -319,17 +324,29 @@ enum {
|
|||
#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */
|
||||
#define B43_MACCTL_GMODE 0x80000000 /* G Mode */
|
||||
|
||||
/* 802.11 core specific TM State Low flags */
|
||||
/* MAC Command bitfield */
|
||||
#define B43_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */
|
||||
#define B43_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */
|
||||
#define B43_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */
|
||||
#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */
|
||||
#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */
|
||||
|
||||
/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
|
||||
#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
|
||||
#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */
|
||||
#define B43_TMSLOW_PHYCLKSPEED 0x00C00000 /* PHY clock speed mask (N-PHY only) */
|
||||
#define B43_TMSLOW_PHYCLKSPEED_40MHZ 0x00000000 /* 40 MHz PHY */
|
||||
#define B43_TMSLOW_PHYCLKSPEED_80MHZ 0x00400000 /* 80 MHz PHY */
|
||||
#define B43_TMSLOW_PHYCLKSPEED_160MHZ 0x00800000 /* 160 MHz PHY */
|
||||
#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select (rev >= 5) */
|
||||
#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
|
||||
#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
|
||||
#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
|
||||
|
||||
/* 802.11 core specific TM State High flags */
|
||||
/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */
|
||||
#define B43_TMSHIGH_DUALBAND_PHY 0x00080000 /* Dualband PHY available */
|
||||
#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */
|
||||
#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */
|
||||
#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */
|
||||
#define B43_TMSHIGH_HAVE_5GHZ_PHY 0x00020000 /* 5 GHz PHY available (rev >= 5) */
|
||||
#define B43_TMSHIGH_HAVE_2GHZ_PHY 0x00010000 /* 2.4 GHz PHY available (rev >= 5) */
|
||||
|
||||
/* Generic-Interrupt reasons. */
|
||||
#define B43_IRQ_MAC_SUSPENDED 0x00000001
|
||||
|
@ -391,6 +408,8 @@ enum {
|
|||
#define B43_DEFAULT_SHORT_RETRY_LIMIT 7
|
||||
#define B43_DEFAULT_LONG_RETRY_LIMIT 4
|
||||
|
||||
#define B43_PHY_TX_BADNESS_LIMIT 1000
|
||||
|
||||
/* Max size of a security key */
|
||||
#define B43_SEC_KEYSIZE 16
|
||||
/* Security algorithms. */
|
||||
|
@ -443,10 +462,6 @@ struct b43_phy {
|
|||
u8 possible_phymodes;
|
||||
/* GMODE bit enabled? */
|
||||
bool gmode;
|
||||
/* Possible ieee80211 subsystem hwmodes for this PHY.
|
||||
* Which mode is selected, depends on thr GMODE enabled bit */
|
||||
#define B43_MAX_PHYHWMODES 2
|
||||
struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
|
||||
|
||||
/* Analog Type */
|
||||
u8 analog;
|
||||
|
@ -460,7 +475,6 @@ struct b43_phy {
|
|||
u16 radio_ver; /* Radio version */
|
||||
u8 radio_rev; /* Radio revision */
|
||||
|
||||
bool locked; /* Only used in b43_phy_{un}lock() */
|
||||
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
|
||||
|
||||
/* ACI (adjacent channel interference) flags. */
|
||||
|
@ -497,11 +511,6 @@ struct b43_phy {
|
|||
s16 lna_gain; /* LNA */
|
||||
s16 pga_gain; /* PGA */
|
||||
|
||||
/* PHY lock for core.rev < 3
|
||||
* This lock is only used by b43_phy_{un}lock()
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/* Desired TX power level (in dBm).
|
||||
* This is set by the user and adjusted in b43_phy_xmitpower(). */
|
||||
u8 power_level;
|
||||
|
@ -512,9 +521,7 @@ struct b43_phy {
|
|||
struct b43_bbatt bbatt;
|
||||
struct b43_rfatt rfatt;
|
||||
u8 tx_control; /* B43_TXCTL_XXX */
|
||||
#ifdef CONFIG_B43_DEBUG
|
||||
bool manual_txpower_control; /* Manual TX-power control enabled? */
|
||||
#endif
|
||||
|
||||
/* Hardware Power Control enabled? */
|
||||
bool hardware_power_control;
|
||||
|
||||
|
@ -542,6 +549,26 @@ struct b43_phy {
|
|||
u16 lofcal;
|
||||
|
||||
u16 initval; //FIXME rename?
|
||||
|
||||
/* PHY TX errors counter. */
|
||||
atomic_t txerr_cnt;
|
||||
|
||||
/* The device does address auto increment for the OFDM tables.
|
||||
* We cache the previously used address here and omit the address
|
||||
* write on the next table access, if possible. */
|
||||
u16 ofdmtab_addr; /* The address currently set in hardware. */
|
||||
enum { /* The last data flow direction. */
|
||||
B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
|
||||
B43_OFDMTAB_DIRECTION_READ,
|
||||
B43_OFDMTAB_DIRECTION_WRITE,
|
||||
} ofdmtab_addr_direction;
|
||||
|
||||
#if B43_DEBUG
|
||||
/* Manual TX-power control enabled? */
|
||||
bool manual_txpower_control;
|
||||
/* PHY registers locked by b43_phy_lock()? */
|
||||
bool phy_locked;
|
||||
#endif /* B43_DEBUG */
|
||||
};
|
||||
|
||||
/* Data structures for DMA transmission, per 80211 core. */
|
||||
|
@ -557,14 +584,6 @@ struct b43_dma {
|
|||
struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
|
||||
};
|
||||
|
||||
/* Data structures for PIO transmission, per 80211 core. */
|
||||
struct b43_pio {
|
||||
struct b43_pioqueue *queue0;
|
||||
struct b43_pioqueue *queue1;
|
||||
struct b43_pioqueue *queue2;
|
||||
struct b43_pioqueue *queue3;
|
||||
};
|
||||
|
||||
/* Context information for a noise calculation (Link Quality). */
|
||||
struct b43_noise_calculation {
|
||||
u8 channel_at_start;
|
||||
|
@ -597,18 +616,18 @@ struct b43_wl {
|
|||
/* Pointer to the ieee80211 hardware data structure */
|
||||
struct ieee80211_hw *hw;
|
||||
|
||||
spinlock_t irq_lock;
|
||||
struct mutex mutex;
|
||||
spinlock_t irq_lock;
|
||||
/* Lock for LEDs access. */
|
||||
spinlock_t leds_lock;
|
||||
/* Lock for SHM access. */
|
||||
spinlock_t shm_lock;
|
||||
|
||||
/* We can only have one operating interface (802.11 core)
|
||||
* at a time. General information about this interface follows.
|
||||
*/
|
||||
|
||||
/* Opaque ID of the operating interface from the ieee80211
|
||||
* subsystem. Do not modify.
|
||||
*/
|
||||
int if_id;
|
||||
struct ieee80211_vif *vif;
|
||||
/* The MAC address of the operating interface. */
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
/* Current BSSID */
|
||||
|
@ -632,18 +651,33 @@ struct b43_wl {
|
|||
/* List of all wireless devices on this chip */
|
||||
struct list_head devlist;
|
||||
u8 nr_devs;
|
||||
|
||||
bool radiotap_enabled;
|
||||
|
||||
/* The beacon we are currently using (AP or IBSS mode).
|
||||
* This beacon stuff is protected by the irq_lock. */
|
||||
struct sk_buff *current_beacon;
|
||||
bool beacon0_uploaded;
|
||||
bool beacon1_uploaded;
|
||||
};
|
||||
|
||||
/* In-memory representation of a cached microcode file. */
|
||||
struct b43_firmware_file {
|
||||
const char *filename;
|
||||
const struct firmware *data;
|
||||
};
|
||||
|
||||
/* Pointers to the firmware data and meta information about it. */
|
||||
struct b43_firmware {
|
||||
/* Microcode */
|
||||
const struct firmware *ucode;
|
||||
struct b43_firmware_file ucode;
|
||||
/* PCM code */
|
||||
const struct firmware *pcm;
|
||||
struct b43_firmware_file pcm;
|
||||
/* Initial MMIO values for the firmware */
|
||||
const struct firmware *initvals;
|
||||
struct b43_firmware_file initvals;
|
||||
/* Initial MMIO values for the firmware, band-specific */
|
||||
const struct firmware *initvals_band;
|
||||
struct b43_firmware_file initvals_band;
|
||||
|
||||
/* Firmware revision */
|
||||
u16 rev;
|
||||
/* Firmware patchlevel */
|
||||
|
@ -681,21 +715,16 @@ struct b43_wldev {
|
|||
/* Saved init status for handling suspend. */
|
||||
int suspend_init_status;
|
||||
|
||||
bool __using_pio; /* Internal, use b43_using_pio(). */
|
||||
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
|
||||
bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */
|
||||
bool short_preamble; /* TRUE, if short preamble is enabled. */
|
||||
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
|
||||
bool short_slot; /* TRUE, if short slot timing is enabled. */
|
||||
bool radio_hw_enable; /* saved state of radio hardware enabled state */
|
||||
|
||||
/* PHY/Radio device. */
|
||||
struct b43_phy phy;
|
||||
union {
|
||||
/* DMA engines. */
|
||||
struct b43_dma dma;
|
||||
/* PIO engines. */
|
||||
struct b43_pio pio;
|
||||
};
|
||||
|
||||
/* DMA engines. */
|
||||
struct b43_dma dma;
|
||||
|
||||
/* Various statistics about the physical device. */
|
||||
struct b43_stats stats;
|
||||
|
@ -730,9 +759,6 @@ struct b43_wldev {
|
|||
u8 max_nr_keys;
|
||||
struct b43_key key[58];
|
||||
|
||||
/* Cached beacon template while uploading the template. */
|
||||
struct sk_buff *cached_beacon;
|
||||
|
||||
/* Firmware data */
|
||||
struct b43_firmware fw;
|
||||
|
||||
|
@ -750,28 +776,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
|
|||
return hw->priv;
|
||||
}
|
||||
|
||||
/* Helper function, which returns a boolean.
|
||||
* TRUE, if PIO is used; FALSE, if DMA is used.
|
||||
*/
|
||||
#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
|
||||
static inline int b43_using_pio(struct b43_wldev *dev)
|
||||
{
|
||||
return dev->__using_pio;
|
||||
}
|
||||
#elif defined(CONFIG_B43_DMA)
|
||||
static inline int b43_using_pio(struct b43_wldev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#elif defined(CONFIG_B43_PIO)
|
||||
static inline int b43_using_pio(struct b43_wldev *dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
# error "Using neither DMA nor PIO? Confused..."
|
||||
#endif
|
||||
|
||||
static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
|
||||
{
|
||||
struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
|
||||
/* 32bit DMA ops. */
|
||||
static
|
||||
|
@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
|
|||
addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
|
||||
addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
|
||||
>> SSB_DMA_TRANSLATION_SHIFT;
|
||||
addrhi |= ssb_dma_translation(ring->dev->dev);
|
||||
addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
|
||||
if (slot == ring->nr_slots - 1)
|
||||
ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
|
||||
if (start)
|
||||
|
@ -315,29 +317,27 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
|
|||
case 3:
|
||||
ring = dev->dma.tx_ring0;
|
||||
break;
|
||||
case 4:
|
||||
ring = dev->dma.tx_ring4;
|
||||
break;
|
||||
case 5:
|
||||
ring = dev->dma.tx_ring5;
|
||||
break;
|
||||
}
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
||||
/* Bcm43xx-ring to mac80211-queue mapping */
|
||||
/* b43-ring to mac80211-queue mapping */
|
||||
static inline int txring_to_priority(struct b43_dmaring *ring)
|
||||
{
|
||||
static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
|
||||
static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
|
||||
unsigned int index;
|
||||
|
||||
/*FIXME: have only one queue, for now */
|
||||
return 0;
|
||||
|
||||
return idx_to_prio[ring->index];
|
||||
index = ring->index;
|
||||
if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
|
||||
index = 0;
|
||||
return idx_to_prio[index];
|
||||
}
|
||||
|
||||
u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
|
||||
static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
|
||||
{
|
||||
static const u16 map64[] = {
|
||||
B43_MMIO_DMA64_BASE0,
|
||||
|
@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
|
|||
B43_MMIO_DMA32_BASE5,
|
||||
};
|
||||
|
||||
if (dma64bit) {
|
||||
if (type == B43_DMA_64BIT) {
|
||||
B43_WARN_ON(!(controller_idx >= 0 &&
|
||||
controller_idx < ARRAY_SIZE(map64)));
|
||||
return map64[controller_idx];
|
||||
|
@ -426,9 +426,21 @@ static inline
|
|||
static int alloc_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
struct device *dev = ring->dev->dev->dev;
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
|
||||
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
|
||||
* has shown that 4K is sufficient for the latter as long as the buffer
|
||||
* does not cross an 8K boundary.
|
||||
*
|
||||
* For unknown reasons - possibly a hardware error - the BCM4311 rev
|
||||
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
|
||||
* which accounts for the GFP_DMA flag below.
|
||||
*/
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), GFP_KERNEL);
|
||||
&(ring->dmabase), flags);
|
||||
if (!ring->descbase) {
|
||||
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
|
@ -447,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
|
|||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
||||
static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
|
||||
enum b43_dmatype type)
|
||||
{
|
||||
int i;
|
||||
u32 value;
|
||||
|
@ -455,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
|||
|
||||
might_sleep();
|
||||
|
||||
offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
|
||||
offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
|
||||
b43_write32(dev, mmio_base + offset, 0);
|
||||
for (i = 0; i < 10; i++) {
|
||||
offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
|
||||
offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
|
||||
B43_DMA32_RXSTATUS;
|
||||
value = b43_read32(dev, mmio_base + offset);
|
||||
if (dma64) {
|
||||
if (type == B43_DMA_64BIT) {
|
||||
value &= B43_DMA64_RXSTAT;
|
||||
if (value == B43_DMA64_RXSTAT_DISABLED) {
|
||||
i = -1;
|
||||
|
@ -483,8 +497,9 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
||||
/* Reset the TX DMA channel */
|
||||
static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
|
||||
enum b43_dmatype type)
|
||||
{
|
||||
int i;
|
||||
u32 value;
|
||||
|
@ -493,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
|||
might_sleep();
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
|
||||
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
|
||||
B43_DMA32_TXSTATUS;
|
||||
value = b43_read32(dev, mmio_base + offset);
|
||||
if (dma64) {
|
||||
if (type == B43_DMA_64BIT) {
|
||||
value &= B43_DMA64_TXSTAT;
|
||||
if (value == B43_DMA64_TXSTAT_DISABLED ||
|
||||
value == B43_DMA64_TXSTAT_IDLEWAIT ||
|
||||
|
@ -510,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
|||
}
|
||||
msleep(1);
|
||||
}
|
||||
offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
|
||||
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
|
||||
b43_write32(dev, mmio_base + offset, 0);
|
||||
for (i = 0; i < 10; i++) {
|
||||
offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
|
||||
offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
|
||||
B43_DMA32_TXSTATUS;
|
||||
value = b43_read32(dev, mmio_base + offset);
|
||||
if (dma64) {
|
||||
if (type == B43_DMA_64BIT) {
|
||||
value &= B43_DMA64_TXSTAT;
|
||||
if (value == B43_DMA64_TXSTAT_DISABLED) {
|
||||
i = -1;
|
||||
|
@ -540,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a DMA mapping address is invalid. */
|
||||
static bool b43_dma_mapping_error(struct b43_dmaring *ring,
|
||||
dma_addr_t addr,
|
||||
size_t buffersize)
|
||||
{
|
||||
if (unlikely(dma_mapping_error(addr)))
|
||||
return 1;
|
||||
|
||||
switch (ring->type) {
|
||||
case B43_DMA_30BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 30))
|
||||
return 1;
|
||||
break;
|
||||
case B43_DMA_32BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 32))
|
||||
return 1;
|
||||
break;
|
||||
case B43_DMA_64BIT:
|
||||
/* Currently we can't have addresses beyond
|
||||
* 64bit in the kernel. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* The address is OK. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
||||
struct b43_dmadesc_generic *desc,
|
||||
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
|
||||
|
@ -555,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
|||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
|
||||
if (dma_mapping_error(dmaaddr)) {
|
||||
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
|
||||
/* ugh. try to realloc in zone_dma */
|
||||
gfp_flags |= GFP_DMA;
|
||||
|
||||
|
@ -568,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
|||
ring->rx_buffersize, 0);
|
||||
}
|
||||
|
||||
if (dma_mapping_error(dmaaddr)) {
|
||||
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -633,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
|
|||
u32 trans = ssb_dma_translation(ring->dev->dev);
|
||||
|
||||
if (ring->tx) {
|
||||
if (ring->dma64) {
|
||||
if (ring->type == B43_DMA_64BIT) {
|
||||
u64 ringbase = (u64) (ring->dmabase);
|
||||
|
||||
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
|
||||
|
@ -647,7 +691,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
|
|||
b43_dma_write(ring, B43_DMA64_TXRINGHI,
|
||||
((ringbase >> 32) &
|
||||
~SSB_DMA_TRANSLATION_MASK)
|
||||
| trans);
|
||||
| (trans << 1));
|
||||
} else {
|
||||
u32 ringbase = (u32) (ring->dmabase);
|
||||
|
||||
|
@ -665,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
|
|||
err = alloc_initial_descbuffers(ring);
|
||||
if (err)
|
||||
goto out;
|
||||
if (ring->dma64) {
|
||||
if (ring->type == B43_DMA_64BIT) {
|
||||
u64 ringbase = (u64) (ring->dmabase);
|
||||
|
||||
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
|
||||
|
@ -680,8 +724,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
|
|||
b43_dma_write(ring, B43_DMA64_RXRINGHI,
|
||||
((ringbase >> 32) &
|
||||
~SSB_DMA_TRANSLATION_MASK)
|
||||
| trans);
|
||||
b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
|
||||
| (trans << 1));
|
||||
b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
|
||||
sizeof(struct b43_dmadesc64));
|
||||
} else {
|
||||
u32 ringbase = (u32) (ring->dmabase);
|
||||
|
||||
|
@ -695,11 +740,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
|
|||
b43_dma_write(ring, B43_DMA32_RXRING,
|
||||
(ringbase & ~SSB_DMA_TRANSLATION_MASK)
|
||||
| trans);
|
||||
b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
|
||||
b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
|
||||
sizeof(struct b43_dmadesc32));
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -708,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
|
|||
{
|
||||
if (ring->tx) {
|
||||
b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
|
||||
ring->dma64);
|
||||
if (ring->dma64) {
|
||||
ring->type);
|
||||
if (ring->type == B43_DMA_64BIT) {
|
||||
b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
|
||||
b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
|
||||
} else
|
||||
b43_dma_write(ring, B43_DMA32_TXRING, 0);
|
||||
} else {
|
||||
b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
|
||||
ring->dma64);
|
||||
if (ring->dma64) {
|
||||
ring->type);
|
||||
if (ring->type == B43_DMA_64BIT) {
|
||||
b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
|
||||
b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
|
||||
} else
|
||||
|
@ -772,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
|
|||
static
|
||||
struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
||||
int controller_index,
|
||||
int for_tx, int dma64)
|
||||
int for_tx,
|
||||
enum b43_dmatype type)
|
||||
{
|
||||
struct b43_dmaring *ring;
|
||||
int err;
|
||||
|
@ -782,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
||||
if (!ring)
|
||||
goto out;
|
||||
ring->type = type;
|
||||
|
||||
nr_slots = B43_RXRING_SLOTS;
|
||||
if (for_tx)
|
||||
|
@ -793,7 +841,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
goto err_kfree_ring;
|
||||
if (for_tx) {
|
||||
ring->txhdr_cache = kcalloc(nr_slots,
|
||||
sizeof(struct b43_txhdr_fw4),
|
||||
b43_txhdr_size(dev),
|
||||
GFP_KERNEL);
|
||||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
|
@ -801,39 +849,38 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
/* test for ability to dma to txhdr_cache */
|
||||
dma_test = dma_map_single(dev->dev->dev,
|
||||
ring->txhdr_cache,
|
||||
sizeof(struct b43_txhdr_fw4),
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(dma_test)) {
|
||||
if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
|
||||
/* ugh realloc */
|
||||
kfree(ring->txhdr_cache);
|
||||
ring->txhdr_cache = kcalloc(nr_slots,
|
||||
sizeof(struct
|
||||
b43_txhdr_fw4),
|
||||
b43_txhdr_size(dev),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
|
||||
dma_test = dma_map_single(dev->dev->dev,
|
||||
ring->txhdr_cache,
|
||||
sizeof(struct b43_txhdr_fw4),
|
||||
b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(dma_test))
|
||||
if (b43_dma_mapping_error(ring, dma_test,
|
||||
b43_txhdr_size(dev)))
|
||||
goto err_kfree_txhdr_cache;
|
||||
}
|
||||
|
||||
dma_unmap_single(dev->dev->dev,
|
||||
dma_test, sizeof(struct b43_txhdr_fw4),
|
||||
dma_test, b43_txhdr_size(dev),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
ring->dev = dev;
|
||||
ring->nr_slots = nr_slots;
|
||||
ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
|
||||
ring->mmio_base = b43_dmacontroller_base(type, controller_index);
|
||||
ring->index = controller_index;
|
||||
ring->dma64 = !!dma64;
|
||||
if (dma64)
|
||||
if (type == B43_DMA_64BIT)
|
||||
ring->ops = &dma64_ops;
|
||||
else
|
||||
ring->ops = &dma32_ops;
|
||||
|
@ -883,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
|
|||
if (!ring)
|
||||
return;
|
||||
|
||||
b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
|
||||
(ring->dma64) ? "64" : "32",
|
||||
b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
|
||||
(unsigned int)(ring->type),
|
||||
ring->mmio_base,
|
||||
(ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
|
||||
/* Device IRQs are disabled prior entering this function,
|
||||
|
@ -901,11 +948,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
|
|||
|
||||
void b43_dma_free(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_dma *dma;
|
||||
|
||||
if (b43_using_pio(dev))
|
||||
return;
|
||||
dma = &dev->dma;
|
||||
struct b43_dma *dma = &dev->dma;
|
||||
|
||||
b43_destroy_dmaring(dma->rx_ring3);
|
||||
dma->rx_ring3 = NULL;
|
||||
|
@ -932,74 +975,78 @@ int b43_dma_init(struct b43_wldev *dev)
|
|||
struct b43_dmaring *ring;
|
||||
int err;
|
||||
u64 dmamask;
|
||||
int dma64 = 0;
|
||||
enum b43_dmatype type;
|
||||
|
||||
dmamask = supported_dma_mask(dev);
|
||||
if (dmamask == DMA_64BIT_MASK)
|
||||
dma64 = 1;
|
||||
|
||||
switch (dmamask) {
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
case DMA_30BIT_MASK:
|
||||
type = B43_DMA_30BIT;
|
||||
break;
|
||||
case DMA_32BIT_MASK:
|
||||
type = B43_DMA_32BIT;
|
||||
break;
|
||||
case DMA_64BIT_MASK:
|
||||
type = B43_DMA_64BIT;
|
||||
break;
|
||||
}
|
||||
err = ssb_dma_set_mask(dev->dev, dmamask);
|
||||
if (err) {
|
||||
#ifdef B43_PIO
|
||||
b43warn(dev->wl, "DMA for this device not supported. "
|
||||
"Falling back to PIO\n");
|
||||
dev->__using_pio = 1;
|
||||
return -EAGAIN;
|
||||
#else
|
||||
b43err(dev->wl, "DMA for this device not supported and "
|
||||
"no PIO support compiled in\n");
|
||||
b43err(dev->wl, "The machine/kernel does not support "
|
||||
"the required DMA mask (0x%08X%08X)\n",
|
||||
(unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
|
||||
(unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
/* setup TX DMA channels. */
|
||||
ring = b43_setup_dmaring(dev, 0, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 0, 1, type);
|
||||
if (!ring)
|
||||
goto out;
|
||||
dma->tx_ring0 = ring;
|
||||
|
||||
ring = b43_setup_dmaring(dev, 1, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 1, 1, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx0;
|
||||
dma->tx_ring1 = ring;
|
||||
|
||||
ring = b43_setup_dmaring(dev, 2, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 2, 1, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx1;
|
||||
dma->tx_ring2 = ring;
|
||||
|
||||
ring = b43_setup_dmaring(dev, 3, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 3, 1, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx2;
|
||||
dma->tx_ring3 = ring;
|
||||
|
||||
ring = b43_setup_dmaring(dev, 4, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 4, 1, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx3;
|
||||
dma->tx_ring4 = ring;
|
||||
|
||||
ring = b43_setup_dmaring(dev, 5, 1, dma64);
|
||||
ring = b43_setup_dmaring(dev, 5, 1, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx4;
|
||||
dma->tx_ring5 = ring;
|
||||
|
||||
/* setup RX DMA channels. */
|
||||
ring = b43_setup_dmaring(dev, 0, 0, dma64);
|
||||
ring = b43_setup_dmaring(dev, 0, 0, type);
|
||||
if (!ring)
|
||||
goto err_destroy_tx5;
|
||||
dma->rx_ring0 = ring;
|
||||
|
||||
if (dev->dev->id.revision < 5) {
|
||||
ring = b43_setup_dmaring(dev, 3, 0, dma64);
|
||||
ring = b43_setup_dmaring(dev, 3, 0, type);
|
||||
if (!ring)
|
||||
goto err_destroy_rx0;
|
||||
dma->rx_ring3 = ring;
|
||||
}
|
||||
|
||||
b43dbg(dev->wl, "%d-bit DMA initialized\n",
|
||||
(dmamask == DMA_64BIT_MASK) ? 64 :
|
||||
(dmamask == DMA_32BIT_MASK) ? 32 : 30);
|
||||
b43dbg(dev->wl, "%u-bit DMA initialized\n",
|
||||
(unsigned int)type);
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
|
@ -1038,26 +1085,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
|
|||
* in the lower 12 bits.
|
||||
* Note that the cookie must never be 0, as this
|
||||
* is a special value used in RX path.
|
||||
* It can also not be 0xFFFF because that is special
|
||||
* for multicast frames.
|
||||
*/
|
||||
switch (ring->index) {
|
||||
case 0:
|
||||
cookie = 0xA000;
|
||||
cookie = 0x1000;
|
||||
break;
|
||||
case 1:
|
||||
cookie = 0xB000;
|
||||
cookie = 0x2000;
|
||||
break;
|
||||
case 2:
|
||||
cookie = 0xC000;
|
||||
cookie = 0x3000;
|
||||
break;
|
||||
case 3:
|
||||
cookie = 0xD000;
|
||||
cookie = 0x4000;
|
||||
break;
|
||||
case 4:
|
||||
cookie = 0xE000;
|
||||
cookie = 0x5000;
|
||||
break;
|
||||
case 5:
|
||||
cookie = 0xF000;
|
||||
cookie = 0x6000;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
B43_WARN_ON(slot & ~0x0FFF);
|
||||
cookie |= (u16) slot;
|
||||
|
@ -1073,22 +1124,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
|
|||
struct b43_dmaring *ring = NULL;
|
||||
|
||||
switch (cookie & 0xF000) {
|
||||
case 0xA000:
|
||||
case 0x1000:
|
||||
ring = dma->tx_ring0;
|
||||
break;
|
||||
case 0xB000:
|
||||
case 0x2000:
|
||||
ring = dma->tx_ring1;
|
||||
break;
|
||||
case 0xC000:
|
||||
case 0x3000:
|
||||
ring = dma->tx_ring2;
|
||||
break;
|
||||
case 0xD000:
|
||||
case 0x4000:
|
||||
ring = dma->tx_ring3;
|
||||
break;
|
||||
case 0xE000:
|
||||
case 0x5000:
|
||||
ring = dma->tx_ring4;
|
||||
break;
|
||||
case 0xF000:
|
||||
case 0x6000:
|
||||
ring = dma->tx_ring5;
|
||||
break;
|
||||
default:
|
||||
|
@ -1106,32 +1157,45 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
|||
{
|
||||
const struct b43_dma_ops *ops = ring->ops;
|
||||
u8 *header;
|
||||
int slot;
|
||||
int slot, old_top_slot, old_used_slots;
|
||||
int err;
|
||||
struct b43_dmadesc_generic *desc;
|
||||
struct b43_dmadesc_meta *meta;
|
||||
struct b43_dmadesc_meta *meta_hdr;
|
||||
struct sk_buff *bounce_skb;
|
||||
u16 cookie;
|
||||
size_t hdrsize = b43_txhdr_size(ring->dev);
|
||||
|
||||
#define SLOTS_PER_PACKET 2
|
||||
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
|
||||
|
||||
old_top_slot = ring->current_slot;
|
||||
old_used_slots = ring->used_slots;
|
||||
|
||||
/* Get a slot for the header. */
|
||||
slot = request_slot(ring);
|
||||
desc = ops->idx2desc(ring, slot, &meta_hdr);
|
||||
memset(meta_hdr, 0, sizeof(*meta_hdr));
|
||||
|
||||
header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
|
||||
b43_generate_txhdr(ring->dev, header,
|
||||
skb->data, skb->len, ctl,
|
||||
generate_cookie(ring, slot));
|
||||
header = &(ring->txhdr_cache[slot * hdrsize]);
|
||||
cookie = generate_cookie(ring, slot);
|
||||
err = b43_generate_txhdr(ring->dev, header,
|
||||
skb->data, skb->len, ctl, cookie);
|
||||
if (unlikely(err)) {
|
||||
ring->current_slot = old_top_slot;
|
||||
ring->used_slots = old_used_slots;
|
||||
return err;
|
||||
}
|
||||
|
||||
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
|
||||
sizeof(struct b43_txhdr_fw4), 1);
|
||||
if (dma_mapping_error(meta_hdr->dmaaddr))
|
||||
hdrsize, 1);
|
||||
if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
|
||||
ring->current_slot = old_top_slot;
|
||||
ring->used_slots = old_used_slots;
|
||||
return -EIO;
|
||||
}
|
||||
ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
|
||||
sizeof(struct b43_txhdr_fw4), 1, 0, 0);
|
||||
hdrsize, 1, 0, 0);
|
||||
|
||||
/* Get a slot for the payload. */
|
||||
slot = request_slot(ring);
|
||||
|
@ -1144,9 +1208,11 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
|||
|
||||
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
|
||||
/* create a bounce buffer in zone_dma on mapping failure. */
|
||||
if (dma_mapping_error(meta->dmaaddr)) {
|
||||
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
|
||||
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
|
||||
if (!bounce_skb) {
|
||||
ring->current_slot = old_top_slot;
|
||||
ring->used_slots = old_used_slots;
|
||||
err = -ENOMEM;
|
||||
goto out_unmap_hdr;
|
||||
}
|
||||
|
@ -1156,7 +1222,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
|||
skb = bounce_skb;
|
||||
meta->skb = skb;
|
||||
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
|
||||
if (dma_mapping_error(meta->dmaaddr)) {
|
||||
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
|
||||
ring->current_slot = old_top_slot;
|
||||
ring->used_slots = old_used_slots;
|
||||
err = -EIO;
|
||||
goto out_free_bounce;
|
||||
}
|
||||
|
@ -1164,16 +1232,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
|||
|
||||
ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
|
||||
|
||||
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
|
||||
/* Tell the firmware about the cookie of the last
|
||||
* mcast frame, so it can clear the more-data bit in it. */
|
||||
b43_shm_write16(ring->dev, B43_SHM_SHARED,
|
||||
B43_SHM_SH_MCASTCOOKIE, cookie);
|
||||
}
|
||||
/* Now transfer the whole frame. */
|
||||
wmb();
|
||||
ops->poke_tx(ring, next_slot(ring, slot));
|
||||
return 0;
|
||||
|
||||
out_free_bounce:
|
||||
out_free_bounce:
|
||||
dev_kfree_skb_any(skb);
|
||||
out_unmap_hdr:
|
||||
out_unmap_hdr:
|
||||
unmap_descbuffer(ring, meta_hdr->dmaaddr,
|
||||
sizeof(struct b43_txhdr_fw4), 1);
|
||||
hdrsize, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1202,10 +1276,27 @@ int b43_dma_tx(struct b43_wldev *dev,
|
|||
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
|
||||
{
|
||||
struct b43_dmaring *ring;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
ring = priority_to_txring(dev, ctl->queue);
|
||||
if (unlikely(skb->len < 2 + 2 + 6)) {
|
||||
/* Too short, this can't be a valid frame. */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
|
||||
/* The multicast ring will be sent after the DTIM */
|
||||
ring = dev->dma.tx_ring4;
|
||||
/* Set the more-data bit. Ucode will clear it on
|
||||
* the last frame for us. */
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
} else {
|
||||
/* Decide by priority where to put this frame. */
|
||||
ring = priority_to_txring(dev, ctl->queue);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ring->lock, flags);
|
||||
B43_WARN_ON(!ring->tx);
|
||||
if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
|
||||
|
@ -1219,6 +1310,13 @@ int b43_dma_tx(struct b43_wldev *dev,
|
|||
B43_WARN_ON(ring->stopped);
|
||||
|
||||
err = dma_tx_fragment(ring, skb, ctl);
|
||||
if (unlikely(err == -ENOKEY)) {
|
||||
/* Drop this packet, as we don't have the encryption key
|
||||
* anymore and must not transmit it unencrypted. */
|
||||
dev_kfree_skb_any(skb);
|
||||
err = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (unlikely(err)) {
|
||||
b43err(dev->wl, "DMA tx mapping failure\n");
|
||||
goto out_unlock;
|
||||
|
@ -1233,7 +1331,7 @@ int b43_dma_tx(struct b43_wldev *dev,
|
|||
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&ring->lock, flags);
|
||||
|
||||
return err;
|
||||
|
@ -1265,7 +1363,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
|||
1);
|
||||
else
|
||||
unmap_descbuffer(ring, meta->dmaaddr,
|
||||
sizeof(struct b43_txhdr_fw4), 1);
|
||||
b43_txhdr_size(dev), 1);
|
||||
|
||||
if (meta->is_last_fragment) {
|
||||
B43_WARN_ON(!meta->skb);
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -65,12 +65,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
|
|||
tuple_t tuple;
|
||||
cisparse_t parse;
|
||||
int err = -ENOMEM;
|
||||
int res;
|
||||
int res = 0;
|
||||
unsigned char buf[64];
|
||||
|
||||
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
|
||||
if (!ssb)
|
||||
goto out;
|
||||
goto out_error;
|
||||
|
||||
err = -ENODEV;
|
||||
tuple.DesiredTuple = CISTPL_CONFIG;
|
||||
|
@ -96,10 +96,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
|
|||
dev->io.NumPorts2 = 0;
|
||||
dev->io.Attributes2 = 0;
|
||||
|
||||
win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
|
||||
win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
|
||||
WIN_ENABLE | WIN_DATA_WIDTH_16 |
|
||||
WIN_USE_WAIT;
|
||||
win.Base = 0;
|
||||
win.Size = SSB_CORE_SIZE;
|
||||
win.AccessSpeed = 1000;
|
||||
win.AccessSpeed = 250;
|
||||
res = pcmcia_request_window(&dev, &win, &dev->win);
|
||||
if (res != CS_SUCCESS)
|
||||
goto err_kfree_ssb;
|
||||
|
@ -108,21 +110,34 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
|
|||
mem.Page = 0;
|
||||
res = pcmcia_map_mem_page(dev->win, &mem);
|
||||
if (res != CS_SUCCESS)
|
||||
goto err_kfree_ssb;
|
||||
goto err_disable;
|
||||
|
||||
dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
|
||||
dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
|
||||
dev->irq.Handler = NULL; /* The handler is registered later. */
|
||||
dev->irq.Instance = NULL;
|
||||
res = pcmcia_request_irq(dev, &dev->irq);
|
||||
if (res != CS_SUCCESS)
|
||||
goto err_disable;
|
||||
|
||||
res = pcmcia_request_configuration(dev, &dev->conf);
|
||||
if (res != CS_SUCCESS)
|
||||
goto err_disable;
|
||||
|
||||
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
|
||||
if (err)
|
||||
goto err_disable;
|
||||
dev->priv = ssb;
|
||||
|
||||
out:
|
||||
return err;
|
||||
err_disable:
|
||||
return 0;
|
||||
|
||||
err_disable:
|
||||
pcmcia_disable_device(dev);
|
||||
err_kfree_ssb:
|
||||
err_kfree_ssb:
|
||||
kfree(ssb);
|
||||
out_error:
|
||||
printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
|
||||
res, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -131,22 +146,21 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
|
|||
struct ssb_bus *ssb = dev->priv;
|
||||
|
||||
ssb_bus_unregister(ssb);
|
||||
pcmcia_release_window(dev->win);
|
||||
pcmcia_disable_device(dev);
|
||||
kfree(ssb);
|
||||
dev->priv = NULL;
|
||||
}
|
||||
|
||||
static struct pcmcia_driver b43_pcmcia_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.drv = {
|
||||
.name = "b43-pcmcia",
|
||||
},
|
||||
.id_table = b43_pcmcia_tbl,
|
||||
.probe = b43_pcmcia_probe,
|
||||
.remove = b43_pcmcia_remove,
|
||||
.suspend = b43_pcmcia_suspend,
|
||||
.resume = b43_pcmcia_resume,
|
||||
.owner = THIS_MODULE,
|
||||
.drv = {
|
||||
.name = "b43-pcmcia",
|
||||
},
|
||||
.id_table = b43_pcmcia_tbl,
|
||||
.probe = b43_pcmcia_probe,
|
||||
.remove = __devexit_p(b43_pcmcia_remove),
|
||||
.suspend = b43_pcmcia_suspend,
|
||||
.resume = b43_pcmcia_resume,
|
||||
};
|
||||
|
||||
int b43_pcmcia_init(void)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -25,6 +25,8 @@
|
|||
#include "rfkill.h"
|
||||
#include "b43.h"
|
||||
|
||||
#include <linux/kmod.h>
|
||||
|
||||
|
||||
/* Returns TRUE, if the radio is enabled in hardware. */
|
||||
static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
|
||||
|
@ -47,32 +49,44 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
|
|||
struct b43_wldev *dev = poll_dev->private;
|
||||
struct b43_wl *wl = dev->wl;
|
||||
bool enabled;
|
||||
bool report_change = 0;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
|
||||
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
|
||||
mutex_unlock(&wl->mutex);
|
||||
return;
|
||||
}
|
||||
enabled = b43_is_hw_radio_enabled(dev);
|
||||
if (unlikely(enabled != dev->radio_hw_enable)) {
|
||||
dev->radio_hw_enable = enabled;
|
||||
report_change = 1;
|
||||
b43info(wl, "Radio hardware status changed to %s\n",
|
||||
enabled ? "ENABLED" : "DISABLED");
|
||||
mutex_unlock(&wl->mutex);
|
||||
input_report_key(poll_dev->input, KEY_WLAN, enabled);
|
||||
} else
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
/* send the radio switch event to the system - note both a key press
|
||||
* and a release are required */
|
||||
if (unlikely(report_change)) {
|
||||
input_report_key(poll_dev->input, KEY_WLAN, 1);
|
||||
input_report_key(poll_dev->input, KEY_WLAN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when the RFKILL toggled in software.
|
||||
* This is called without locking. */
|
||||
/* Called when the RFKILL toggled in software. */
|
||||
static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
||||
{
|
||||
struct b43_wldev *dev = data;
|
||||
struct b43_wl *wl = dev->wl;
|
||||
int err = 0;
|
||||
int err = -EBUSY;
|
||||
|
||||
if (!wl->rfkill.registered)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
if (b43_status(dev) < B43_STAT_INITIALIZED)
|
||||
goto out_unlock;
|
||||
|
||||
err = 0;
|
||||
switch (state) {
|
||||
case RFKILL_STATE_ON:
|
||||
if (!dev->radio_hw_enable) {
|
||||
|
@ -89,7 +103,6 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|||
b43_radio_turn_off(dev, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
|
@ -98,11 +111,11 @@ out_unlock:
|
|||
|
||||
char * b43_rfkill_led_name(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
struct b43_rfkill *rfk = &(dev->wl->rfkill);
|
||||
|
||||
if (!wl->rfkill.rfkill)
|
||||
if (!rfk->registered)
|
||||
return NULL;
|
||||
return rfkill_get_led_name(wl->rfkill.rfkill);
|
||||
return rfkill_get_led_name(rfk->rfkill);
|
||||
}
|
||||
|
||||
void b43_rfkill_init(struct b43_wldev *dev)
|
||||
|
@ -111,53 +124,13 @@ void b43_rfkill_init(struct b43_wldev *dev)
|
|||
struct b43_rfkill *rfk = &(wl->rfkill);
|
||||
int err;
|
||||
|
||||
if (rfk->rfkill) {
|
||||
err = rfkill_register(rfk->rfkill);
|
||||
if (err) {
|
||||
b43warn(wl, "Failed to register RF-kill button\n");
|
||||
goto err_free_rfk;
|
||||
}
|
||||
}
|
||||
if (rfk->poll_dev) {
|
||||
err = input_register_polled_device(rfk->poll_dev);
|
||||
if (err) {
|
||||
b43warn(wl, "Failed to register RF-kill polldev\n");
|
||||
goto err_free_polldev;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
err_free_rfk:
|
||||
rfkill_free(rfk->rfkill);
|
||||
rfk->rfkill = NULL;
|
||||
err_free_polldev:
|
||||
input_free_polled_device(rfk->poll_dev);
|
||||
rfk->poll_dev = NULL;
|
||||
}
|
||||
|
||||
void b43_rfkill_exit(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_rfkill *rfk = &(dev->wl->rfkill);
|
||||
|
||||
if (rfk->poll_dev)
|
||||
input_unregister_polled_device(rfk->poll_dev);
|
||||
if (rfk->rfkill)
|
||||
rfkill_unregister(rfk->rfkill);
|
||||
}
|
||||
|
||||
void b43_rfkill_alloc(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
struct b43_rfkill *rfk = &(wl->rfkill);
|
||||
|
||||
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) {
|
||||
rfk->poll_dev->private = dev;
|
||||
rfk->poll_dev->poll = b43_rfkill_poll;
|
||||
rfk->poll_dev->poll_interval = 1000; /* msecs */
|
||||
} else
|
||||
b43warn(wl, "Failed to allocate RF-kill polldev\n");
|
||||
if (!rfk->poll_dev) {
|
||||
rfkill_free(rfk->rfkill);
|
||||
goto err_freed_rfk;
|
||||
}
|
||||
|
||||
rfk->poll_dev->private = dev;
|
||||
rfk->poll_dev->poll = b43_rfkill_poll;
|
||||
rfk->poll_dev->poll_interval = 1000; /* msecs */
|
||||
|
||||
rfk->poll_dev->input->name = rfk->name;
|
||||
rfk->poll_dev->input->id.bustype = BUS_HOST;
|
||||
rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
|
||||
rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
|
||||
|
||||
err = rfkill_register(rfk->rfkill);
|
||||
if (err)
|
||||
goto err_free_polldev;
|
||||
|
||||
#ifdef CONFIG_RFKILL_INPUT_MODULE
|
||||
/* B43 RF-kill isn't useful without the rfkill-input subsystem.
|
||||
* Try to load the module. */
|
||||
err = request_module("rfkill-input");
|
||||
if (err)
|
||||
b43warn(wl, "Failed to load the rfkill-input module. "
|
||||
"The built-in radio LED will not work.\n");
|
||||
#endif /* CONFIG_RFKILL_INPUT */
|
||||
|
||||
err = input_register_polled_device(rfk->poll_dev);
|
||||
if (err)
|
||||
goto err_unreg_rfk;
|
||||
|
||||
rfk->registered = 1;
|
||||
|
||||
return;
|
||||
err_unreg_rfk:
|
||||
rfkill_unregister(rfk->rfkill);
|
||||
err_free_polldev:
|
||||
input_free_polled_device(rfk->poll_dev);
|
||||
rfk->poll_dev = NULL;
|
||||
err_freed_rfk:
|
||||
rfk->rfkill = NULL;
|
||||
out_error:
|
||||
rfk->registered = 0;
|
||||
b43warn(wl, "RF-kill button init failed\n");
|
||||
}
|
||||
|
||||
void b43_rfkill_free(struct b43_wldev *dev)
|
||||
void b43_rfkill_exit(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_rfkill *rfk = &(dev->wl->rfkill);
|
||||
|
||||
if (!rfk->registered)
|
||||
return;
|
||||
rfk->registered = 0;
|
||||
|
||||
input_unregister_polled_device(rfk->poll_dev);
|
||||
rfkill_unregister(rfk->rfkill);
|
||||
input_free_polled_device(rfk->poll_dev);
|
||||
rfk->poll_dev = NULL;
|
||||
rfkill_free(rfk->rfkill);
|
||||
rfk->rfkill = NULL;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef B43_TABLES_H_
|
||||
#define B43_TABLES_H_
|
||||
|
||||
#define B43_TAB_ROTOR_SIZE 53
|
||||
#define B43_TAB_ROTOR_SIZE 53
|
||||
extern const u32 b43_tab_rotor[];
|
||||
#define B43_TAB_RETARD_SIZE 53
|
||||
#define B43_TAB_RETARD_SIZE 53
|
||||
extern const u32 b43_tab_retard[];
|
||||
#define B43_TAB_FINEFREQA_SIZE 256
|
||||
extern const u16 b43_tab_finefreqa[];
|
||||
|
@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[];
|
|||
extern const u16 b43_tab_noiseg1[];
|
||||
#define B43_TAB_NOISEG2_SIZE 8
|
||||
extern const u16 b43_tab_noiseg2[];
|
||||
#define B43_TAB_NOISESCALEG_SIZE 27
|
||||
#define B43_TAB_NOISESCALE_SIZE 27
|
||||
extern const u16 b43_tab_noisescalea2[];
|
||||
extern const u16 b43_tab_noisescalea3[];
|
||||
extern const u16 b43_tab_noisescaleg1[];
|
||||
extern const u16 b43_tab_noisescaleg2[];
|
||||
extern const u16 b43_tab_noisescaleg3[];
|
||||
#define B43_TAB_SIGMASQR_SIZE 53
|
||||
extern const u16 b43_tab_sigmasqr1[];
|
||||
extern const u16 b43_tab_sigmasqr2[];
|
||||
#define B43_TAB_RSSIAGC1_SIZE 16
|
||||
extern const u16 b43_tab_rssiagc1[];
|
||||
#define B43_TAB_RSSIAGC2_SIZE 48
|
||||
extern const u16 b43_tab_rssiagc2[];
|
||||
|
||||
#endif /* B43_TABLES_H_ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -5,7 +5,7 @@
|
|||
Transmission (TX/RX) related functions.
|
||||
|
||||
Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
|
||||
Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
|
||||
Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
|
||||
Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
|
||||
Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
|
||||
Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
|
||||
|
@ -30,48 +30,50 @@
|
|||
#include "xmit.h"
|
||||
#include "phy.h"
|
||||
#include "dma.h"
|
||||
#include "pio.h"
|
||||
|
||||
/* Extract the bitrate out of a CCK PLCP header. */
|
||||
static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
|
||||
|
||||
/* Extract the bitrate index out of a CCK PLCP header. */
|
||||
static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
|
||||
{
|
||||
switch (plcp->raw[0]) {
|
||||
case 0x0A:
|
||||
return B43_CCK_RATE_1MB;
|
||||
return 0;
|
||||
case 0x14:
|
||||
return B43_CCK_RATE_2MB;
|
||||
return 1;
|
||||
case 0x37:
|
||||
return B43_CCK_RATE_5MB;
|
||||
return 2;
|
||||
case 0x6E:
|
||||
return B43_CCK_RATE_11MB;
|
||||
return 3;
|
||||
}
|
||||
B43_WARN_ON(1);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract the bitrate out of an OFDM PLCP header. */
|
||||
static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
|
||||
/* Extract the bitrate index out of an OFDM PLCP header. */
|
||||
static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
|
||||
{
|
||||
int base = aphy ? 0 : 4;
|
||||
|
||||
switch (plcp->raw[0] & 0xF) {
|
||||
case 0xB:
|
||||
return B43_OFDM_RATE_6MB;
|
||||
return base + 0;
|
||||
case 0xF:
|
||||
return B43_OFDM_RATE_9MB;
|
||||
return base + 1;
|
||||
case 0xA:
|
||||
return B43_OFDM_RATE_12MB;
|
||||
return base + 2;
|
||||
case 0xE:
|
||||
return B43_OFDM_RATE_18MB;
|
||||
return base + 3;
|
||||
case 0x9:
|
||||
return B43_OFDM_RATE_24MB;
|
||||
return base + 4;
|
||||
case 0xD:
|
||||
return B43_OFDM_RATE_36MB;
|
||||
return base + 5;
|
||||
case 0x8:
|
||||
return B43_OFDM_RATE_48MB;
|
||||
return base + 6;
|
||||
case 0xC:
|
||||
return B43_OFDM_RATE_54MB;
|
||||
return base + 7;
|
||||
}
|
||||
B43_WARN_ON(1);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
|
||||
|
@ -177,18 +179,21 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void generate_txhdr_fw4(struct b43_wldev *dev,
|
||||
struct b43_txhdr_fw4 *txhdr,
|
||||
const unsigned char *fragment_data,
|
||||
unsigned int fragment_len,
|
||||
const struct ieee80211_tx_control *txctl,
|
||||
u16 cookie)
|
||||
/* Generate a TX data header. */
|
||||
int b43_generate_txhdr(struct b43_wldev *dev,
|
||||
u8 *_txhdr,
|
||||
const unsigned char *fragment_data,
|
||||
unsigned int fragment_len,
|
||||
const struct ieee80211_tx_control *txctl,
|
||||
u16 cookie)
|
||||
{
|
||||
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
|
||||
const struct b43_phy *phy = &dev->phy;
|
||||
const struct ieee80211_hdr *wlhdr =
|
||||
(const struct ieee80211_hdr *)fragment_data;
|
||||
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
|
||||
u16 fctl = le16_to_cpu(wlhdr->frame_control);
|
||||
struct ieee80211_rate *fbrate;
|
||||
u8 rate, rate_fb;
|
||||
int rate_ofdm, rate_fb_ofdm;
|
||||
unsigned int plcp_fragment_len;
|
||||
|
@ -198,9 +203,11 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
|
||||
memset(txhdr, 0, sizeof(*txhdr));
|
||||
|
||||
rate = txctl->tx_rate;
|
||||
WARN_ON(!txctl->tx_rate);
|
||||
rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
|
||||
rate_ofdm = b43_is_ofdm_rate(rate);
|
||||
rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
|
||||
fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
|
||||
rate_fb = fbrate->hw_value;
|
||||
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
|
||||
|
||||
if (rate_ofdm)
|
||||
|
@ -219,11 +226,10 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
* use the original dur_id field. */
|
||||
txhdr->dur_fb = wlhdr->duration_id;
|
||||
} else {
|
||||
int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
|
||||
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->if_id,
|
||||
txctl->vif,
|
||||
fragment_len,
|
||||
fbrate_base100kbps);
|
||||
fbrate);
|
||||
}
|
||||
|
||||
plcp_fragment_len = fragment_len + FCS_LEN;
|
||||
|
@ -235,29 +241,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
|
||||
B43_WARN_ON(key_idx >= dev->max_nr_keys);
|
||||
key = &(dev->key[key_idx]);
|
||||
B43_WARN_ON(!key->keyconf);
|
||||
|
||||
if (unlikely(!key->keyconf)) {
|
||||
/* This key is invalid. This might only happen
|
||||
* in a short timeframe after machine resume before
|
||||
* we were able to reconfigure keys.
|
||||
* Drop this packet completely. Do not transmit it
|
||||
* unencrypted to avoid leaking information. */
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
/* Hardware appends ICV. */
|
||||
plcp_fragment_len += txctl->icv_len;
|
||||
|
||||
key_idx = b43_kidx_to_fw(dev, key_idx);
|
||||
mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
|
||||
B43_TX4_MAC_KEYIDX;
|
||||
mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
|
||||
B43_TX4_MAC_KEYALG;
|
||||
mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
|
||||
B43_TXH_MAC_KEYIDX;
|
||||
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
|
||||
B43_TXH_MAC_KEYALG;
|
||||
wlhdr_len = ieee80211_get_hdrlen(fctl);
|
||||
iv_len = min((size_t) txctl->iv_len,
|
||||
ARRAY_SIZE(txhdr->iv));
|
||||
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
|
||||
}
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
|
||||
plcp_fragment_len, rate);
|
||||
if (b43_is_old_txhdr_format(dev)) {
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
|
||||
plcp_fragment_len, rate);
|
||||
} else {
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
|
||||
plcp_fragment_len, rate);
|
||||
}
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
|
||||
plcp_fragment_len, rate_fb);
|
||||
|
||||
/* Extra Frame Types */
|
||||
if (rate_fb_ofdm)
|
||||
extra_ft |= B43_TX4_EFT_FBOFDM;
|
||||
extra_ft |= B43_TXH_EFT_FB_OFDM;
|
||||
else
|
||||
extra_ft |= B43_TXH_EFT_FB_CCK;
|
||||
|
||||
/* Set channel radio code. Note that the micrcode ORs 0x100 to
|
||||
* this value before comparing it to the value in SHM, if this
|
||||
|
@ -267,18 +288,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
|
||||
/* PHY TX Control word */
|
||||
if (rate_ofdm)
|
||||
phy_ctl |= B43_TX4_PHY_OFDM;
|
||||
if (dev->short_preamble)
|
||||
phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
|
||||
switch (txctl->antenna_sel_tx) {
|
||||
case 0:
|
||||
phy_ctl |= B43_TX4_PHY_ANTLAST;
|
||||
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
|
||||
else
|
||||
phy_ctl |= B43_TXH_PHY_ENC_CCK;
|
||||
if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
|
||||
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
|
||||
|
||||
switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
|
||||
case 0: /* Default */
|
||||
phy_ctl |= B43_TXH_PHY_ANT01AUTO;
|
||||
break;
|
||||
case 1:
|
||||
phy_ctl |= B43_TX4_PHY_ANT0;
|
||||
case 1: /* Antenna 0 */
|
||||
phy_ctl |= B43_TXH_PHY_ANT0;
|
||||
break;
|
||||
case 2:
|
||||
phy_ctl |= B43_TX4_PHY_ANT1;
|
||||
case 2: /* Antenna 1 */
|
||||
phy_ctl |= B43_TXH_PHY_ANT1;
|
||||
break;
|
||||
case 3: /* Antenna 2 */
|
||||
phy_ctl |= B43_TXH_PHY_ANT2;
|
||||
break;
|
||||
case 4: /* Antenna 3 */
|
||||
phy_ctl |= B43_TXH_PHY_ANT3;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
|
@ -286,14 +316,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
|
||||
/* MAC control */
|
||||
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
|
||||
mac_ctl |= B43_TX4_MAC_ACK;
|
||||
mac_ctl |= B43_TXH_MAC_ACK;
|
||||
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
|
||||
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
|
||||
mac_ctl |= B43_TX4_MAC_HWSEQ;
|
||||
mac_ctl |= B43_TXH_MAC_HWSEQ;
|
||||
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
|
||||
mac_ctl |= B43_TX4_MAC_STMSDU;
|
||||
mac_ctl |= B43_TXH_MAC_STMSDU;
|
||||
if (phy->type == B43_PHYTYPE_A)
|
||||
mac_ctl |= B43_TX4_MAC_5GHZ;
|
||||
mac_ctl |= B43_TXH_MAC_5GHZ;
|
||||
if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
|
||||
mac_ctl |= B43_TXH_MAC_LONGFRAME;
|
||||
|
||||
/* Generate the RTS or CTS-to-self frame */
|
||||
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
|
||||
|
@ -302,66 +334,94 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
|
|||
struct ieee80211_hdr *hdr;
|
||||
int rts_rate, rts_rate_fb;
|
||||
int rts_rate_ofdm, rts_rate_fb_ofdm;
|
||||
struct b43_plcp_hdr6 *plcp;
|
||||
|
||||
rts_rate = txctl->rts_cts_rate;
|
||||
WARN_ON(!txctl->rts_cts_rate);
|
||||
rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
|
||||
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
|
||||
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
|
||||
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
|
||||
|
||||
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
|
||||
ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
|
||||
struct ieee80211_cts *cts;
|
||||
|
||||
if (b43_is_old_txhdr_format(dev)) {
|
||||
cts = (struct ieee80211_cts *)
|
||||
(txhdr->old_format.rts_frame);
|
||||
} else {
|
||||
cts = (struct ieee80211_cts *)
|
||||
(txhdr->new_format.rts_frame);
|
||||
}
|
||||
ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
|
||||
fragment_data, fragment_len,
|
||||
txctl,
|
||||
(struct ieee80211_cts *)(txhdr->
|
||||
rts_frame));
|
||||
mac_ctl |= B43_TX4_MAC_SENDCTS;
|
||||
txctl, cts);
|
||||
mac_ctl |= B43_TXH_MAC_SENDCTS;
|
||||
len = sizeof(struct ieee80211_cts);
|
||||
} else {
|
||||
ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
|
||||
fragment_data, fragment_len, txctl,
|
||||
(struct ieee80211_rts *)(txhdr->
|
||||
rts_frame));
|
||||
mac_ctl |= B43_TX4_MAC_SENDRTS;
|
||||
struct ieee80211_rts *rts;
|
||||
|
||||
if (b43_is_old_txhdr_format(dev)) {
|
||||
rts = (struct ieee80211_rts *)
|
||||
(txhdr->old_format.rts_frame);
|
||||
} else {
|
||||
rts = (struct ieee80211_rts *)
|
||||
(txhdr->new_format.rts_frame);
|
||||
}
|
||||
ieee80211_rts_get(dev->wl->hw, txctl->vif,
|
||||
fragment_data, fragment_len,
|
||||
txctl, rts);
|
||||
mac_ctl |= B43_TXH_MAC_SENDRTS;
|
||||
len = sizeof(struct ieee80211_rts);
|
||||
}
|
||||
len += FCS_LEN;
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
|
||||
rts_plcp), len,
|
||||
rts_rate);
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
|
||||
rts_plcp_fb),
|
||||
|
||||
/* Generate the PLCP headers for the RTS/CTS frame */
|
||||
if (b43_is_old_txhdr_format(dev))
|
||||
plcp = &txhdr->old_format.rts_plcp;
|
||||
else
|
||||
plcp = &txhdr->new_format.rts_plcp;
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
|
||||
len, rts_rate);
|
||||
plcp = &txhdr->rts_plcp_fb;
|
||||
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
|
||||
len, rts_rate_fb);
|
||||
hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
|
||||
|
||||
if (b43_is_old_txhdr_format(dev)) {
|
||||
hdr = (struct ieee80211_hdr *)
|
||||
(&txhdr->old_format.rts_frame);
|
||||
} else {
|
||||
hdr = (struct ieee80211_hdr *)
|
||||
(&txhdr->new_format.rts_frame);
|
||||
}
|
||||
txhdr->rts_dur_fb = hdr->duration_id;
|
||||
|
||||
if (rts_rate_ofdm) {
|
||||
extra_ft |= B43_TX4_EFT_RTSOFDM;
|
||||
extra_ft |= B43_TXH_EFT_RTS_OFDM;
|
||||
txhdr->phy_rate_rts =
|
||||
b43_plcp_get_ratecode_ofdm(rts_rate);
|
||||
} else
|
||||
} else {
|
||||
extra_ft |= B43_TXH_EFT_RTS_CCK;
|
||||
txhdr->phy_rate_rts =
|
||||
b43_plcp_get_ratecode_cck(rts_rate);
|
||||
}
|
||||
if (rts_rate_fb_ofdm)
|
||||
extra_ft |= B43_TX4_EFT_RTSFBOFDM;
|
||||
mac_ctl |= B43_TX4_MAC_LONGFRAME;
|
||||
extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
|
||||
else
|
||||
extra_ft |= B43_TXH_EFT_RTSFB_CCK;
|
||||
}
|
||||
|
||||
/* Magic cookie */
|
||||
txhdr->cookie = cpu_to_le16(cookie);
|
||||
if (b43_is_old_txhdr_format(dev))
|
||||
txhdr->old_format.cookie = cpu_to_le16(cookie);
|
||||
else
|
||||
txhdr->new_format.cookie = cpu_to_le16(cookie);
|
||||
|
||||
/* Apply the bitfields */
|
||||
txhdr->mac_ctl = cpu_to_le32(mac_ctl);
|
||||
txhdr->phy_ctl = cpu_to_le16(phy_ctl);
|
||||
txhdr->extra_ft = extra_ft;
|
||||
}
|
||||
|
||||
void b43_generate_txhdr(struct b43_wldev *dev,
|
||||
u8 * txhdr,
|
||||
const unsigned char *fragment_data,
|
||||
unsigned int fragment_len,
|
||||
const struct ieee80211_tx_control *txctl, u16 cookie)
|
||||
{
|
||||
generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
|
||||
fragment_data, fragment_len, txctl, cookie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s8 b43_rssi_postprocess(struct b43_wldev *dev,
|
||||
|
@ -384,7 +444,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
|
|||
else
|
||||
tmp -= 3;
|
||||
} else {
|
||||
if (dev->dev->bus->sprom.r1.
|
||||
if (dev->dev->bus->sprom.
|
||||
boardflags_lo & B43_BFL_RSSI) {
|
||||
if (in_rssi > 63)
|
||||
in_rssi = 63;
|
||||
|
@ -451,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
u16 phystat0, phystat3, chanstat, mactime;
|
||||
u32 macstat;
|
||||
u16 chanid;
|
||||
u16 phytype;
|
||||
u8 jssi;
|
||||
int padding;
|
||||
|
||||
|
@ -463,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
macstat = le32_to_cpu(rxhdr->mac_status);
|
||||
mactime = le16_to_cpu(rxhdr->mac_time);
|
||||
chanstat = le16_to_cpu(rxhdr->channel);
|
||||
phytype = chanstat & B43_RX_CHAN_PHYTYPE;
|
||||
|
||||
if (macstat & B43_RX_MAC_FCSERR)
|
||||
dev->wl->ieee_stats.dot11FCSErrorCount++;
|
||||
|
@ -488,7 +550,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
}
|
||||
wlhdr = (struct ieee80211_hdr *)(skb->data);
|
||||
fctl = le16_to_cpu(wlhdr->frame_control);
|
||||
skb_trim(skb, skb->len - FCS_LEN);
|
||||
|
||||
if (macstat & B43_RX_MAC_DEC) {
|
||||
unsigned int keyidx;
|
||||
|
@ -521,31 +582,59 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
/* the next line looks wrong, but is what mac80211 wants */
|
||||
status.signal = (jssi * 100) / B43_RX_MAX_SSI;
|
||||
if (phystat0 & B43_RX_PHYST0_OFDM)
|
||||
status.rate = b43_plcp_get_bitrate_ofdm(plcp);
|
||||
status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
|
||||
phytype == B43_PHYTYPE_A);
|
||||
else
|
||||
status.rate = b43_plcp_get_bitrate_cck(plcp);
|
||||
status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
|
||||
status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
|
||||
status.mactime = mactime;
|
||||
|
||||
/*
|
||||
* If monitors are present get full 64-bit timestamp. This
|
||||
* code assumes we get to process the packet within 16 bits
|
||||
* of timestamp, i.e. about 65 milliseconds after the PHY
|
||||
* received the first symbol.
|
||||
*/
|
||||
if (dev->wl->radiotap_enabled) {
|
||||
u16 low_mactime_now;
|
||||
|
||||
b43_tsf_read(dev, &status.mactime);
|
||||
low_mactime_now = status.mactime;
|
||||
status.mactime = status.mactime & ~0xFFFFULL;
|
||||
status.mactime += mactime;
|
||||
if (low_mactime_now <= mactime)
|
||||
status.mactime -= 0x10000;
|
||||
status.flag |= RX_FLAG_TSFT;
|
||||
}
|
||||
|
||||
chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
|
||||
switch (chanstat & B43_RX_CHAN_PHYTYPE) {
|
||||
case B43_PHYTYPE_A:
|
||||
status.phymode = MODE_IEEE80211A;
|
||||
status.freq = chanid;
|
||||
status.channel = b43_freq_to_channel_a(chanid);
|
||||
break;
|
||||
case B43_PHYTYPE_B:
|
||||
status.phymode = MODE_IEEE80211B;
|
||||
status.freq = chanid + 2400;
|
||||
status.channel = b43_freq_to_channel_bg(chanid + 2400);
|
||||
status.band = IEEE80211_BAND_5GHZ;
|
||||
B43_WARN_ON(1);
|
||||
/* FIXME: We don't really know which value the "chanid" contains.
|
||||
* So the following assignment might be wrong. */
|
||||
status.freq = b43_channel_to_freq_5ghz(chanid);
|
||||
break;
|
||||
case B43_PHYTYPE_G:
|
||||
status.phymode = MODE_IEEE80211G;
|
||||
status.band = IEEE80211_BAND_2GHZ;
|
||||
/* chanid is the radio channel cookie value as used
|
||||
* to tune the radio. */
|
||||
status.freq = chanid + 2400;
|
||||
status.channel = b43_freq_to_channel_bg(chanid + 2400);
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
/* chanid is the SHM channel cookie. Which is the plain
|
||||
* channel number in b43. */
|
||||
if (chanstat & B43_RX_CHAN_5GHZ) {
|
||||
status.band = IEEE80211_BAND_5GHZ;
|
||||
status.freq = b43_freq_to_channel_5ghz(chanid);
|
||||
} else {
|
||||
status.band = IEEE80211_BAND_2GHZ;
|
||||
status.freq = b43_freq_to_channel_2ghz(chanid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dev->stats.last_rx = jiffies;
|
||||
|
@ -575,10 +664,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
|
|||
dev->wl->ieee_stats.dot11RTSSuccessCount++;
|
||||
}
|
||||
|
||||
if (b43_using_pio(dev))
|
||||
b43_pio_handle_txstatus(dev, status);
|
||||
else
|
||||
b43_dma_handle_txstatus(dev, status);
|
||||
b43_dma_handle_txstatus(dev, status);
|
||||
}
|
||||
|
||||
/* Handle TX status report as received through DMA/PIO queues */
|
||||
|
@ -607,19 +693,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
|
|||
/* Stop any TX operation on the device (suspend the hardware queues) */
|
||||
void b43_tx_suspend(struct b43_wldev *dev)
|
||||
{
|
||||
if (b43_using_pio(dev))
|
||||
b43_pio_freeze_txqueues(dev);
|
||||
else
|
||||
b43_dma_tx_suspend(dev);
|
||||
b43_dma_tx_suspend(dev);
|
||||
}
|
||||
|
||||
/* Resume any TX operation on the device (resume the hardware queues) */
|
||||
void b43_tx_resume(struct b43_wldev *dev)
|
||||
{
|
||||
if (b43_using_pio(dev))
|
||||
b43_pio_thaw_txqueues(dev);
|
||||
else
|
||||
b43_dma_tx_resume(dev);
|
||||
b43_dma_tx_resume(dev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -19,74 +19,166 @@ _b43_declare_plcp_hdr(6);
|
|||
#undef _b43_declare_plcp_hdr
|
||||
|
||||
/* TX header for v4 firmware */
|
||||
struct b43_txhdr_fw4 {
|
||||
__le32 mac_ctl; /* MAC TX control */
|
||||
__le16 mac_frame_ctl; /* Copy of the FrameControl field */
|
||||
struct b43_txhdr {
|
||||
__le32 mac_ctl; /* MAC TX control */
|
||||
__le16 mac_frame_ctl; /* Copy of the FrameControl field */
|
||||
__le16 tx_fes_time_norm; /* TX FES Time Normal */
|
||||
__le16 phy_ctl; /* PHY TX control */
|
||||
__le16 phy_ctl_0; /* Unused */
|
||||
__le16 phy_ctl_1; /* Unused */
|
||||
__le16 phy_ctl_rts_0; /* Unused */
|
||||
__le16 phy_ctl_rts_1; /* Unused */
|
||||
__u8 phy_rate; /* PHY rate */
|
||||
__u8 phy_rate_rts; /* PHY rate for RTS/CTS */
|
||||
__u8 extra_ft; /* Extra Frame Types */
|
||||
__u8 chan_radio_code; /* Channel Radio Code */
|
||||
__u8 iv[16]; /* Encryption IV */
|
||||
__u8 tx_receiver[6]; /* TX Frame Receiver address */
|
||||
__le16 tx_fes_time_fb; /* TX FES Time Fallback */
|
||||
struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */
|
||||
__le16 rts_dur_fb; /* RTS fallback duration */
|
||||
struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */
|
||||
__le16 dur_fb; /* Fallback duration */
|
||||
__le16 mm_dur_time; /* Unused */
|
||||
__le16 mm_dur_time_fb; /* Unused */
|
||||
__le32 time_stamp; /* Timestamp */
|
||||
PAD_BYTES(2);
|
||||
__le16 cookie; /* TX frame cookie */
|
||||
__le16 tx_status; /* TX status */
|
||||
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */
|
||||
__u8 rts_frame[16]; /* The RTS frame (if used) */
|
||||
PAD_BYTES(2);
|
||||
struct b43_plcp_hdr6 plcp; /* Main PLCP */
|
||||
__le16 phy_ctl; /* PHY TX control */
|
||||
__le16 phy_ctl1; /* PHY TX control word 1 */
|
||||
__le16 phy_ctl1_fb; /* PHY TX control word 1 for fallback rates */
|
||||
__le16 phy_ctl1_rts; /* PHY TX control word 1 RTS */
|
||||
__le16 phy_ctl1_rts_fb; /* PHY TX control word 1 RTS for fallback rates */
|
||||
__u8 phy_rate; /* PHY rate */
|
||||
__u8 phy_rate_rts; /* PHY rate for RTS/CTS */
|
||||
__u8 extra_ft; /* Extra Frame Types */
|
||||
__u8 chan_radio_code; /* Channel Radio Code */
|
||||
__u8 iv[16]; /* Encryption IV */
|
||||
__u8 tx_receiver[6]; /* TX Frame Receiver address */
|
||||
__le16 tx_fes_time_fb; /* TX FES Time Fallback */
|
||||
struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */
|
||||
__le16 rts_dur_fb; /* RTS fallback duration */
|
||||
struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP header */
|
||||
__le16 dur_fb; /* Fallback duration */
|
||||
__le16 mimo_modelen; /* MIMO mode length */
|
||||
__le16 mimo_ratelen_fb; /* MIMO fallback rate length */
|
||||
__le32 timeout; /* Timeout */
|
||||
|
||||
union {
|
||||
/* The new r410 format. */
|
||||
struct {
|
||||
__le16 mimo_antenna; /* MIMO antenna select */
|
||||
__le16 preload_size; /* Preload size */
|
||||
PAD_BYTES(2);
|
||||
__le16 cookie; /* TX frame cookie */
|
||||
__le16 tx_status; /* TX status */
|
||||
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */
|
||||
__u8 rts_frame[16]; /* The RTS frame (if used) */
|
||||
PAD_BYTES(2);
|
||||
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
|
||||
} new_format __attribute__ ((__packed__));
|
||||
|
||||
/* The old r351 format. */
|
||||
struct {
|
||||
PAD_BYTES(2);
|
||||
__le16 cookie; /* TX frame cookie */
|
||||
__le16 tx_status; /* TX status */
|
||||
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */
|
||||
__u8 rts_frame[16]; /* The RTS frame (if used) */
|
||||
PAD_BYTES(2);
|
||||
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
|
||||
} old_format __attribute__ ((__packed__));
|
||||
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* MAC TX control */
|
||||
#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
|
||||
#define B43_TX4_MAC_KEYIDX_SHIFT 20
|
||||
#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
|
||||
#define B43_TX4_MAC_KEYALG_SHIFT 16
|
||||
#define B43_TX4_MAC_LIFETIME 0x00001000
|
||||
#define B43_TX4_MAC_FRAMEBURST 0x00000800
|
||||
#define B43_TX4_MAC_SENDCTS 0x00000400
|
||||
#define B43_TX4_MAC_AMPDU 0x00000300
|
||||
#define B43_TX4_MAC_AMPDU_SHIFT 8
|
||||
#define B43_TX4_MAC_5GHZ 0x00000080
|
||||
#define B43_TX4_MAC_IGNPMQ 0x00000020
|
||||
#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
|
||||
#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
|
||||
#define B43_TX4_MAC_SENDRTS 0x00000004
|
||||
#define B43_TX4_MAC_LONGFRAME 0x00000002
|
||||
#define B43_TX4_MAC_ACK 0x00000001
|
||||
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
|
||||
#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */
|
||||
#define B43_TXH_MAC_KEYIDX_SHIFT 20
|
||||
#define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */
|
||||
#define B43_TXH_MAC_KEYALG_SHIFT 16
|
||||
#define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */
|
||||
#define B43_TXH_MAC_RIFS 0x00004000 /* Use RIFS */
|
||||
#define B43_TXH_MAC_LIFETIME 0x00002000 /* Lifetime */
|
||||
#define B43_TXH_MAC_FRAMEBURST 0x00001000 /* Frameburst */
|
||||
#define B43_TXH_MAC_SENDCTS 0x00000800 /* Send CTS-to-self */
|
||||
#define B43_TXH_MAC_AMPDU 0x00000600 /* AMPDU status */
|
||||
#define B43_TXH_MAC_AMPDU_MPDU 0x00000000 /* Regular MPDU, not an AMPDU */
|
||||
#define B43_TXH_MAC_AMPDU_FIRST 0x00000200 /* First MPDU or AMPDU */
|
||||
#define B43_TXH_MAC_AMPDU_INTER 0x00000400 /* Intermediate MPDU or AMPDU */
|
||||
#define B43_TXH_MAC_AMPDU_LAST 0x00000600 /* Last (or only) MPDU of AMPDU */
|
||||
#define B43_TXH_MAC_40MHZ 0x00000100 /* Use 40 MHz bandwidth */
|
||||
#define B43_TXH_MAC_5GHZ 0x00000080 /* 5GHz band */
|
||||
#define B43_TXH_MAC_DFCS 0x00000040 /* DFCS */
|
||||
#define B43_TXH_MAC_IGNPMQ 0x00000020 /* Ignore PMQ */
|
||||
#define B43_TXH_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
|
||||
#define B43_TXH_MAC_STMSDU 0x00000008 /* Start MSDU */
|
||||
#define B43_TXH_MAC_SENDRTS 0x00000004 /* Send RTS */
|
||||
#define B43_TXH_MAC_LONGFRAME 0x00000002 /* Long frame */
|
||||
#define B43_TXH_MAC_ACK 0x00000001 /* Immediate ACK */
|
||||
|
||||
/* Extra Frame Types */
|
||||
#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */
|
||||
#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
|
||||
#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
|
||||
#define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */
|
||||
#define B43_TXH_EFT_FB_CCK 0x00 /* CCK */
|
||||
#define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */
|
||||
#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */
|
||||
#define B43_TXH_EFT_FB_N 0x03 /* N */
|
||||
#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */
|
||||
#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */
|
||||
#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */
|
||||
#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */
|
||||
#define B43_TXH_EFT_RTS_N 0x0C /* N */
|
||||
#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */
|
||||
#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */
|
||||
#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */
|
||||
#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */
|
||||
#define B43_TXH_EFT_RTSFB_N 0x30 /* N */
|
||||
|
||||
/* PHY TX control word */
|
||||
#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
|
||||
#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
|
||||
#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */
|
||||
#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
|
||||
#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
|
||||
#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
|
||||
#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,
|
||||
u8 * txhdr,
|
||||
const unsigned char *fragment_data,
|
||||
unsigned int fragment_len,
|
||||
const struct ieee80211_tx_control *txctl, u16 cookie);
|
||||
/* PHY TX control word 1 */
|
||||
#define B43_TXH_PHY1_BW 0x0007 /* Bandwidth */
|
||||
#define B43_TXH_PHY1_BW_10 0x0000 /* 10 MHz */
|
||||
#define B43_TXH_PHY1_BW_10U 0x0001 /* 10 MHz upper */
|
||||
#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */
|
||||
#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */
|
||||
#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */
|
||||
#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */
|
||||
#define B43_TXH_PHY1_MODE 0x0038 /* Mode */
|
||||
#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */
|
||||
#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */
|
||||
#define B43_TXH_PHY1_MODE_STBC 0x0010 /* STBC */
|
||||
#define B43_TXH_PHY1_MODE_SDM 0x0018 /* SDM */
|
||||
#define B43_TXH_PHY1_CRATE 0x0700 /* Coding rate */
|
||||
#define B43_TXH_PHY1_CRATE_1_2 0x0000 /* 1/2 */
|
||||
#define B43_TXH_PHY1_CRATE_2_3 0x0100 /* 2/3 */
|
||||
#define B43_TXH_PHY1_CRATE_3_4 0x0200 /* 3/4 */
|
||||
#define B43_TXH_PHY1_CRATE_4_5 0x0300 /* 4/5 */
|
||||
#define B43_TXH_PHY1_CRATE_5_6 0x0400 /* 5/6 */
|
||||
#define B43_TXH_PHY1_CRATE_7_8 0x0600 /* 7/8 */
|
||||
#define B43_TXH_PHY1_MODUL 0x3800 /* Modulation scheme */
|
||||
#define B43_TXH_PHY1_MODUL_BPSK 0x0000 /* BPSK */
|
||||
#define B43_TXH_PHY1_MODUL_QPSK 0x0800 /* QPSK */
|
||||
#define B43_TXH_PHY1_MODUL_QAM16 0x1000 /* QAM16 */
|
||||
#define B43_TXH_PHY1_MODUL_QAM64 0x1800 /* QAM64 */
|
||||
#define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */
|
||||
|
||||
|
||||
/* r351 firmware compatibility stuff. */
|
||||
static inline
|
||||
bool b43_is_old_txhdr_format(struct b43_wldev *dev)
|
||||
{
|
||||
return (dev->fw.rev <= 351);
|
||||
}
|
||||
|
||||
static inline
|
||||
size_t b43_txhdr_size(struct b43_wldev *dev)
|
||||
{
|
||||
if (b43_is_old_txhdr_format(dev))
|
||||
return 100 + sizeof(struct b43_plcp_hdr6);
|
||||
return 104 + sizeof(struct b43_plcp_hdr6);
|
||||
}
|
||||
|
||||
|
||||
int b43_generate_txhdr(struct b43_wldev *dev,
|
||||
u8 * txhdr,
|
||||
const unsigned char *fragment_data,
|
||||
unsigned int fragment_len,
|
||||
const struct ieee80211_tx_control *txctl, u16 cookie);
|
||||
|
||||
/* Transmit Status */
|
||||
struct b43_txstatus {
|
||||
|
@ -142,49 +234,56 @@ struct b43_rxhdr_fw4 {
|
|||
} __attribute__ ((__packed__));
|
||||
|
||||
/* PHY RX Status 0 */
|
||||
#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
|
||||
#define B43_RX_PHYST0_PLCPHCF 0x0200
|
||||
#define B43_RX_PHYST0_PLCPFV 0x0100
|
||||
#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
|
||||
#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
|
||||
#define B43_RX_PHYST0_PLCPHCF 0x0200
|
||||
#define B43_RX_PHYST0_PLCPFV 0x0100
|
||||
#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
|
||||
#define B43_RX_PHYST0_LCRS 0x0040
|
||||
#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */
|
||||
#define B43_RX_PHYST0_UNSRATE 0x0010
|
||||
#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */
|
||||
#define B43_RX_PHYST0_UNSRATE 0x0010
|
||||
#define B43_RX_PHYST0_CLIP 0x000C
|
||||
#define B43_RX_PHYST0_CLIP_SHIFT 2
|
||||
#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */
|
||||
#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
|
||||
#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
|
||||
#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
|
||||
#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
|
||||
#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */
|
||||
#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
|
||||
#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
|
||||
#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
|
||||
#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
|
||||
|
||||
/* PHY RX Status 2 */
|
||||
#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
|
||||
#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
|
||||
#define B43_RX_PHYST2_LNAG_SHIFT 14
|
||||
#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
|
||||
#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
|
||||
#define B43_RX_PHYST2_PNAG_SHIFT 10
|
||||
#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */
|
||||
#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */
|
||||
|
||||
/* PHY RX Status 3 */
|
||||
#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
|
||||
#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
|
||||
#define B43_RX_PHYST3_DIGG_SHIFT 11
|
||||
#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
|
||||
#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
|
||||
|
||||
/* MAC RX Status */
|
||||
#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
|
||||
#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */
|
||||
#define B43_RX_MAC_KEYIDX_SHIFT 5
|
||||
#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */
|
||||
#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */
|
||||
#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
|
||||
#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
|
||||
#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */
|
||||
#define B43_RX_MAC_RXST_VALID 0x01000000 /* PHY RXST valid */
|
||||
#define B43_RX_MAC_TKIP_MICERR 0x00100000 /* TKIP MIC error */
|
||||
#define B43_RX_MAC_TKIP_MICATT 0x00080000 /* TKIP MIC attempted */
|
||||
#define B43_RX_MAC_AGGTYPE 0x00060000 /* Aggregation type */
|
||||
#define B43_RX_MAC_AGGTYPE_SHIFT 17
|
||||
#define B43_RX_MAC_AMSDU 0x00010000 /* A-MSDU mask */
|
||||
#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon sent flag */
|
||||
#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */
|
||||
#define B43_RX_MAC_KEYIDX_SHIFT 5
|
||||
#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */
|
||||
#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */
|
||||
#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
|
||||
#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
|
||||
#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */
|
||||
|
||||
/* RX channel */
|
||||
#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */
|
||||
#define B43_RX_CHAN_GAIN_SHIFT 10
|
||||
#define B43_RX_CHAN_ID 0x03FC /* Channel ID */
|
||||
#define B43_RX_CHAN_ID_SHIFT 2
|
||||
#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
|
||||
#define B43_RX_CHAN_40MHZ 0x1000 /* 40 Mhz channel width */
|
||||
#define B43_RX_CHAN_5GHZ 0x0800 /* 5 Ghz band */
|
||||
#define B43_RX_CHAN_ID 0x07F8 /* Channel ID */
|
||||
#define B43_RX_CHAN_ID_SHIFT 3
|
||||
#define B43_RX_CHAN_PHYTYPE 0x0007 /* PHY type */
|
||||
|
||||
|
||||
u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
|
||||
u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" \
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,470 +0,0 @@
|
|||
Subject: cfg80211/nl80211: introduce key handling
|
||||
|
||||
This introduces key handling to cfg80211/nl80211. Default
|
||||
and group keys can be added, changed and removed; sequence
|
||||
counters for each key can be retrieved.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
---
|
||||
include/linux/nl80211.h | 34 +++++
|
||||
include/net/cfg80211.h | 44 +++++++
|
||||
net/wireless/core.c | 3
|
||||
net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 370 insertions(+)
|
||||
|
||||
--- everything.orig/include/linux/nl80211.h 2007-10-30 15:33:43.587381346 +0100
|
||||
+++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100
|
||||
@@ -37,6 +37,16 @@
|
||||
* userspace to request deletion of a virtual interface, then requires
|
||||
* attribute %NL80211_ATTR_IFINDEX.
|
||||
*
|
||||
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
|
||||
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
|
||||
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
|
||||
+ * %NL80211_ATTR_KEY_THRESHOLD.
|
||||
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
|
||||
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
|
||||
+ * attributes.
|
||||
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
|
||||
+ * or %NL80211_ATTR_MAC.
|
||||
+ *
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -54,6 +64,11 @@ enum nl80211_commands {
|
||||
NL80211_CMD_NEW_INTERFACE,
|
||||
NL80211_CMD_DEL_INTERFACE,
|
||||
|
||||
+ NL80211_CMD_GET_KEY,
|
||||
+ NL80211_CMD_SET_KEY,
|
||||
+ NL80211_CMD_NEW_KEY,
|
||||
+ NL80211_CMD_DEL_KEY,
|
||||
+
|
||||
/* add commands here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@@ -75,6 +90,17 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_IFNAME: network interface name
|
||||
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
|
||||
*
|
||||
+ * @NL80211_ATTR_MAC: MAC address (various uses)
|
||||
+ *
|
||||
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
|
||||
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
|
||||
+ * keys
|
||||
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
|
||||
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
|
||||
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
|
||||
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
|
||||
+ * CCMP keys, each six bytes in little endian
|
||||
+ *
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -89,6 +115,14 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_IFNAME,
|
||||
NL80211_ATTR_IFTYPE,
|
||||
|
||||
+ NL80211_ATTR_MAC,
|
||||
+
|
||||
+ NL80211_ATTR_KEY_DATA,
|
||||
+ NL80211_ATTR_KEY_IDX,
|
||||
+ NL80211_ATTR_KEY_CIPHER,
|
||||
+ NL80211_ATTR_KEY_SEQ,
|
||||
+ NL80211_ATTR_KEY_DEFAULT,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- everything.orig/net/wireless/nl80211.c 2007-10-30 15:33:43.637380153 +0100
|
||||
+++ everything/net/wireless/nl80211.c 2007-11-07 13:19:38.201511066 +0100
|
||||
@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
|
||||
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
|
||||
+
|
||||
+ [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
|
||||
+
|
||||
+ [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
|
||||
+ .len = WLAN_MAX_KEY_LEN },
|
||||
+ [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
|
||||
+ [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
|
||||
+ [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* message building helper */
|
||||
@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct
|
||||
return err;
|
||||
}
|
||||
|
||||
+struct get_key_cookie {
|
||||
+ struct sk_buff *msg;
|
||||
+ int error;
|
||||
+};
|
||||
+
|
||||
+static void get_key_callback(void *c, struct key_params *params)
|
||||
+{
|
||||
+ struct get_key_cookie *cookie = c;
|
||||
+
|
||||
+ if (params->key)
|
||||
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
|
||||
+ params->key_len, params->key);
|
||||
+
|
||||
+ if (params->seq)
|
||||
+ NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
|
||||
+ params->seq_len, params->seq);
|
||||
+
|
||||
+ if (params->cipher)
|
||||
+ NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
|
||||
+ params->cipher);
|
||||
+
|
||||
+ return;
|
||||
+ nla_put_failure:
|
||||
+ cookie->error = 1;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ u8 key_idx = 0;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+ struct get_key_cookie cookie = {
|
||||
+ .error = 0,
|
||||
+ };
|
||||
+ void *hdr;
|
||||
+ struct sk_buff *msg;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
+
|
||||
+ if (key_idx > 3)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_MAC])
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->get_key) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
+ if (!msg) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
|
||||
+ NL80211_CMD_NEW_KEY);
|
||||
+
|
||||
+ if (IS_ERR(hdr)) {
|
||||
+ err = PTR_ERR(hdr);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ cookie.msg = msg;
|
||||
+
|
||||
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
|
||||
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
|
||||
+ if (mac_addr)
|
||||
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
|
||||
+ &cookie, get_key_callback);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (cookie.error)
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ genlmsg_end(msg, hdr);
|
||||
+ err = genlmsg_unicast(msg, info->snd_pid);
|
||||
+ goto out;
|
||||
+
|
||||
+ nla_put_failure:
|
||||
+ err = -ENOBUFS;
|
||||
+ nlmsg_free(msg);
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ u8 key_idx;
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
+
|
||||
+ if (key_idx > 3)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* currently only support setting default key */
|
||||
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->set_default_key) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ struct key_params params;
|
||||
+ u8 key_idx = 0;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+
|
||||
+ memset(¶ms, 0, sizeof(params));
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_KEY_DATA]) {
|
||||
+ params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
|
||||
+ params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
|
||||
+ }
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
+
|
||||
+ params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_MAC])
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+
|
||||
+ if (key_idx > 3)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /*
|
||||
+ * Disallow pairwise keys with non-zero index unless it's WEP
|
||||
+ * (because current deployments use pairwise WEP keys with
|
||||
+ * non-zero indizes but 802.11i clearly specifies to use zero)
|
||||
+ */
|
||||
+ if (mac_addr && key_idx &&
|
||||
+ params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
|
||||
+ params.cipher != WLAN_CIPHER_SUITE_WEP104)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* TODO: add definitions for the lengths to linux/ieee80211.h */
|
||||
+ switch (params.cipher) {
|
||||
+ case WLAN_CIPHER_SUITE_WEP40:
|
||||
+ if (params.key_len != 5)
|
||||
+ return -EINVAL;
|
||||
+ break;
|
||||
+ case WLAN_CIPHER_SUITE_TKIP:
|
||||
+ if (params.key_len != 32)
|
||||
+ return -EINVAL;
|
||||
+ break;
|
||||
+ case WLAN_CIPHER_SUITE_CCMP:
|
||||
+ if (params.key_len != 16)
|
||||
+ return -EINVAL;
|
||||
+ break;
|
||||
+ case WLAN_CIPHER_SUITE_WEP104:
|
||||
+ if (params.key_len != 13)
|
||||
+ return -EINVAL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->add_key) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ u8 key_idx = 0;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
+ key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
+
|
||||
+ if (key_idx > 3)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_MAC])
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->del_key) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static struct genl_ops nl80211_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
@@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_GET_KEY,
|
||||
+ .doit = nl80211_get_key,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_SET_KEY,
|
||||
+ .doit = nl80211_set_key,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_NEW_KEY,
|
||||
+ .doit = nl80211_new_key,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_DEL_KEY,
|
||||
+ .doit = nl80211_del_key,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
};
|
||||
|
||||
/* multicast groups */
|
||||
--- everything.orig/net/wireless/core.c 2007-10-30 15:33:43.677380478 +0100
|
||||
+++ everything/net/wireless/core.c 2007-11-07 13:19:38.221513833 +0100
|
||||
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
|
||||
struct cfg80211_registered_device *drv;
|
||||
int alloc_size;
|
||||
|
||||
+ WARN_ON(!ops->add_key && ops->del_key);
|
||||
+ WARN_ON(ops->add_key && !ops->del_key);
|
||||
+
|
||||
alloc_size = sizeof(*drv) + sizeof_priv;
|
||||
|
||||
drv = kzalloc(alloc_size, GFP_KERNEL);
|
||||
--- everything.orig/include/net/cfg80211.h 2007-10-30 15:33:43.617381780 +0100
|
||||
+++ everything/include/net/cfg80211.h 2007-11-07 13:19:38.231512748 +0100
|
||||
@@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
|
||||
struct ieee80211_radiotap_iterator *iterator);
|
||||
|
||||
|
||||
+ /**
|
||||
+ * struct key_params - key information
|
||||
+ *
|
||||
+ * Information about a key
|
||||
+ *
|
||||
+ * @key: key material
|
||||
+ * @key_len: length of key material
|
||||
+ * @cipher: cipher suite selector
|
||||
+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
|
||||
+ * with the get_key() callback, must be in little endian,
|
||||
+ * length given by @seq_len.
|
||||
+ */
|
||||
+struct key_params {
|
||||
+ u8 *key;
|
||||
+ u8 *seq;
|
||||
+ int key_len;
|
||||
+ int seq_len;
|
||||
+ u32 cipher;
|
||||
+};
|
||||
+
|
||||
/* from net/wireless.h */
|
||||
struct wiphy;
|
||||
|
||||
@@ -71,6 +91,18 @@ struct wiphy;
|
||||
*
|
||||
* @change_virtual_intf: change type of virtual interface
|
||||
*
|
||||
+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
|
||||
+ * when adding a group key.
|
||||
+ *
|
||||
+ * @get_key: get information about the key with the given parameters.
|
||||
+ * @mac_addr will be %NULL when requesting information for a group
|
||||
+ * key. All pointers given to the @callback function need not be valid
|
||||
+ * after it returns.
|
||||
+ *
|
||||
+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
|
||||
+ * and @key_index
|
||||
+ *
|
||||
+ * @set_default_key: set the default key on an interface
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
|
||||
@@ -78,6 +110,18 @@ struct cfg80211_ops {
|
||||
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
|
||||
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
|
||||
enum nl80211_iftype type);
|
||||
+
|
||||
+ int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
|
||||
+ u8 key_index, u8 *mac_addr,
|
||||
+ struct key_params *params);
|
||||
+ int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
|
||||
+ u8 key_index, u8 *mac_addr, void *cookie,
|
||||
+ void (*callback)(void *cookie, struct key_params*));
|
||||
+ int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
|
||||
+ u8 key_index, u8 *mac_addr);
|
||||
+ int (*set_default_key)(struct wiphy *wiphy,
|
||||
+ struct net_device *netdev,
|
||||
+ u8 key_index);
|
||||
};
|
||||
|
||||
#endif /* __NET_CFG80211_H */
|
|
@ -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,
|
||||
};
|
|
@ -1,161 +0,0 @@
|
|||
Subject: mac80211: support getting key sequence counters via cfg80211
|
||||
|
||||
This implements cfg80211's get_key() to allow retrieving the sequence
|
||||
counter for a TKIP or CCMP key from userspace. It also cleans up and
|
||||
documents the associated low-level driver interface.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
---
|
||||
include/net/mac80211.h | 14 ++------
|
||||
net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 89 insertions(+), 10 deletions(-)
|
||||
|
||||
Index: mac80211/net/mac80211/cfg.c
|
||||
===================================================================
|
||||
--- mac80211.orig/net/mac80211/cfg.c 2007-11-11 15:46:41.497954646 +0100
|
||||
+++ mac80211/net/mac80211/cfg.c 2007-11-11 15:46:51.346515884 +0100
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* mac80211 configuration hooks for cfg80211
|
||||
*
|
||||
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
|
||||
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
@@ -180,6 +180,88 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ u8 key_idx, u8 *mac_addr, void *cookie,
|
||||
+ void (*callback)(void *cookie,
|
||||
+ struct key_params *params))
|
||||
+{
|
||||
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
+ struct sta_info *sta = NULL;
|
||||
+ u8 seq[6] = {0};
|
||||
+ struct key_params params;
|
||||
+ struct ieee80211_key *key;
|
||||
+ u32 iv32;
|
||||
+ u16 iv16;
|
||||
+ int err = -ENOENT;
|
||||
+
|
||||
+ if (mac_addr) {
|
||||
+ sta = sta_info_get(sdata->local, mac_addr);
|
||||
+ if (!sta)
|
||||
+ goto out;
|
||||
+
|
||||
+ key = sta->key;
|
||||
+ } else
|
||||
+ key = sdata->keys[key_idx];
|
||||
+
|
||||
+ if (!key)
|
||||
+ goto out;
|
||||
+
|
||||
+ memset(¶ms, 0, sizeof(params));
|
||||
+
|
||||
+ switch (key->conf.alg) {
|
||||
+ case ALG_TKIP:
|
||||
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
|
||||
+
|
||||
+ iv32 = key->u.tkip.iv32;
|
||||
+ iv16 = key->u.tkip.iv16;
|
||||
+
|
||||
+ if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
+ sdata->local->ops->get_tkip_seq)
|
||||
+ sdata->local->ops->get_tkip_seq(
|
||||
+ local_to_hw(sdata->local),
|
||||
+ key->conf.hw_key_idx,
|
||||
+ &iv32, &iv16);
|
||||
+
|
||||
+ seq[0] = iv16 & 0xff;
|
||||
+ seq[1] = (iv16 >> 8) & 0xff;
|
||||
+ seq[2] = iv32 & 0xff;
|
||||
+ seq[3] = (iv32 >> 8) & 0xff;
|
||||
+ seq[4] = (iv32 >> 16) & 0xff;
|
||||
+ seq[5] = (iv32 >> 24) & 0xff;
|
||||
+ params.seq = seq;
|
||||
+ params.seq_len = 6;
|
||||
+ break;
|
||||
+ case ALG_CCMP:
|
||||
+ params.cipher = WLAN_CIPHER_SUITE_CCMP;
|
||||
+ seq[0] = key->u.ccmp.tx_pn[5];
|
||||
+ seq[1] = key->u.ccmp.tx_pn[4];
|
||||
+ seq[2] = key->u.ccmp.tx_pn[3];
|
||||
+ seq[3] = key->u.ccmp.tx_pn[2];
|
||||
+ seq[4] = key->u.ccmp.tx_pn[1];
|
||||
+ seq[5] = key->u.ccmp.tx_pn[0];
|
||||
+ params.seq = seq;
|
||||
+ params.seq_len = 6;
|
||||
+ break;
|
||||
+ case ALG_WEP:
|
||||
+ if (key->conf.keylen == 5)
|
||||
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
|
||||
+ else
|
||||
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ params.key = key->conf.key;
|
||||
+ params.key_len = key->conf.keylen;
|
||||
+
|
||||
+ callback(cookie, ¶ms);
|
||||
+ err = 0;
|
||||
+
|
||||
+ out:
|
||||
+ if (sta)
|
||||
+ sta_info_put(sta);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static int ieee80211_config_default_key(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 key_idx)
|
||||
@@ -198,5 +280,6 @@
|
||||
.change_virtual_intf = ieee80211_change_iface,
|
||||
.add_key = ieee80211_add_key,
|
||||
.del_key = ieee80211_del_key,
|
||||
+ .get_key = ieee80211_get_key,
|
||||
.set_default_key = ieee80211_config_default_key,
|
||||
};
|
||||
Index: mac80211/include/net/mac80211.h
|
||||
===================================================================
|
||||
--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:46:41.377947807 +0100
|
||||
+++ mac80211/include/net/mac80211.h 2007-11-11 15:47:08.183475366 +0100
|
||||
@@ -598,9 +598,6 @@
|
||||
u8 key[0];
|
||||
};
|
||||
|
||||
-#define IEEE80211_SEQ_COUNTER_RX 0
|
||||
-#define IEEE80211_SEQ_COUNTER_TX 1
|
||||
-
|
||||
/**
|
||||
* enum set_key_cmd - key command
|
||||
*
|
||||
@@ -947,9 +944,9 @@
|
||||
*
|
||||
* @get_stats: return low-level statistics
|
||||
*
|
||||
- * @get_sequence_counter: For devices that have internal sequence counters this
|
||||
- * callback allows mac80211 to access the current value of a counter.
|
||||
- * This callback seems not well-defined, tell us if you need it.
|
||||
+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
|
||||
+ * callback should be provided to read the TKIP transmit IVs (both IV32
|
||||
+ * and IV16) for the given key from hardware.
|
||||
*
|
||||
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
|
||||
*
|
||||
@@ -1022,9 +1019,8 @@
|
||||
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
|
||||
int (*get_stats)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats);
|
||||
- int (*get_sequence_counter)(struct ieee80211_hw *hw,
|
||||
- u8* addr, u8 keyidx, u8 txrx,
|
||||
- u32* iv32, u16* iv16);
|
||||
+ void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
||||
+ u32 *iv32, u16 *iv16);
|
||||
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*set_retry_limit)(struct ieee80211_hw *hw,
|
|
@ -1,279 +0,0 @@
|
|||
Subject: cfg80211/nl80211: add beacon settings
|
||||
|
||||
This adds the necessary API to cfg80211/nl80211 to allow
|
||||
changing beaconing settings.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
---
|
||||
include/linux/nl80211.h | 24 ++++++++
|
||||
include/net/cfg80211.h | 33 +++++++++++
|
||||
net/wireless/nl80211.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 190 insertions(+)
|
||||
|
||||
--- everything.orig/include/net/cfg80211.h 2007-11-08 11:50:57.412840007 +0100
|
||||
+++ everything/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
|
||||
@@ -69,6 +69,26 @@ struct key_params {
|
||||
u32 cipher;
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * struct beacon_parameters - beacon parameters
|
||||
+ *
|
||||
+ * Used to configure the beacon for an interface.
|
||||
+ *
|
||||
+ * @head: head portion of beacon (before TIM IE)
|
||||
+ * or %NULL if not changed
|
||||
+ * @tail: tail portion of beacon (after TIM IE)
|
||||
+ * or %NULL if not changed
|
||||
+ * @interval: beacon interval or zero if not changed
|
||||
+ * @dtim_period: DTIM period or zero if not changed
|
||||
+ * @head_len: length of @head
|
||||
+ * @tail_len: length of @tail
|
||||
+ */
|
||||
+struct beacon_parameters {
|
||||
+ u8 *head, *tail;
|
||||
+ int interval, dtim_period;
|
||||
+ int head_len, tail_len;
|
||||
+};
|
||||
+
|
||||
/* from net/wireless.h */
|
||||
struct wiphy;
|
||||
|
||||
@@ -103,6 +123,13 @@ struct wiphy;
|
||||
* and @key_index
|
||||
*
|
||||
* @set_default_key: set the default key on an interface
|
||||
+ *
|
||||
+ * @add_beacon: Add a beacon with given parameters, @head, @interval
|
||||
+ * and @dtim_period will be valid, @tail is optional.
|
||||
+ * @set_beacon: Change the beacon parameters for an access point mode
|
||||
+ * interface. This should reject the call when no beacon has been
|
||||
+ * configured.
|
||||
+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
|
||||
@@ -122,6 +149,12 @@ struct cfg80211_ops {
|
||||
int (*set_default_key)(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
u8 key_index);
|
||||
+
|
||||
+ int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ struct beacon_parameters *info);
|
||||
+ int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ struct beacon_parameters *info);
|
||||
+ int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
|
||||
};
|
||||
|
||||
#endif /* __NET_CFG80211_H */
|
||||
--- everything.orig/include/linux/nl80211.h 2007-11-08 11:50:57.362839952 +0100
|
||||
+++ everything/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
|
||||
@@ -47,6 +47,15 @@
|
||||
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
|
||||
* or %NL80211_ATTR_MAC.
|
||||
*
|
||||
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
|
||||
+ * %NL80222_CMD_NEW_BEACON message)
|
||||
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
|
||||
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
|
||||
+ * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
|
||||
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
|
||||
+ * parameters are like for %NL80211_CMD_SET_BEACON.
|
||||
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
|
||||
+ *
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -69,6 +78,11 @@ enum nl80211_commands {
|
||||
NL80211_CMD_NEW_KEY,
|
||||
NL80211_CMD_DEL_KEY,
|
||||
|
||||
+ NL80211_CMD_GET_BEACON,
|
||||
+ NL80211_CMD_SET_BEACON,
|
||||
+ NL80211_CMD_NEW_BEACON,
|
||||
+ NL80211_CMD_DEL_BEACON,
|
||||
+
|
||||
/* add commands here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@@ -101,6 +115,11 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
|
||||
* CCMP keys, each six bytes in little endian
|
||||
*
|
||||
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
|
||||
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
|
||||
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
|
||||
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
|
||||
+ *
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -123,6 +142,11 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_KEY_SEQ,
|
||||
NL80211_ATTR_KEY_DEFAULT,
|
||||
|
||||
+ NL80211_ATTR_BEACON_INTERVAL,
|
||||
+ NL80211_ATTR_DTIM_PERIOD,
|
||||
+ NL80211_ATTR_BEACON_HEAD,
|
||||
+ NL80211_ATTR_BEACON_TAIL,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- everything.orig/net/wireless/nl80211.c 2007-11-08 11:50:57.382836589 +0100
|
||||
+++ everything/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
|
||||
@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[
|
||||
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
|
||||
+
|
||||
+ [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
|
||||
+ [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
|
||||
+ [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
|
||||
+ .len = IEEE80211_MAX_DATA_LEN },
|
||||
+ [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
|
||||
+ .len = IEEE80211_MAX_DATA_LEN },
|
||||
};
|
||||
|
||||
/* message building helper */
|
||||
@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf
|
||||
return err;
|
||||
}
|
||||
|
||||
+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ int (*call)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ struct beacon_parameters *info);
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ struct beacon_parameters params;
|
||||
+ int haveinfo = 0;
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ switch (info->genlhdr->cmd) {
|
||||
+ case NL80211_CMD_NEW_BEACON:
|
||||
+ /* these are required for NEW_BEACON */
|
||||
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
|
||||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
|
||||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
+ err = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ call = drv->ops->add_beacon;
|
||||
+ break;
|
||||
+ case NL80211_CMD_SET_BEACON:
|
||||
+ call = drv->ops->set_beacon;
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN_ON(1);
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!call) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ memset(¶ms, 0, sizeof(params));
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
|
||||
+ params.interval =
|
||||
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
||||
+ haveinfo = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
|
||||
+ params.dtim_period =
|
||||
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
|
||||
+ haveinfo = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
+ params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
+ params.head_len =
|
||||
+ nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
+ haveinfo = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
|
||||
+ params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
+ params.tail_len =
|
||||
+ nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
+ haveinfo = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (!haveinfo) {
|
||||
+ err = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = call(&drv->wiphy, dev, ¶ms);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->del_beacon) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->del_beacon(&drv->wiphy, dev);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static struct genl_ops nl80211_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_SET_BEACON,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ .doit = nl80211_addset_beacon,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_NEW_BEACON,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ .doit = nl80211_addset_beacon,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_DEL_BEACON,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ .doit = nl80211_del_beacon,
|
||||
+ },
|
||||
};
|
||||
|
||||
/* multicast groups */
|
|
@ -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));
|
|
@ -1,464 +0,0 @@
|
|||
Subject: cfg80211/nl80211: station handling
|
||||
|
||||
This patch adds station handling to cfg80211/nl80211.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
---
|
||||
include/linux/nl80211.h | 68 +++++++++++++
|
||||
include/net/cfg80211.h | 54 ++++++++++
|
||||
net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 358 insertions(+)
|
||||
|
||||
--- everything.orig/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100
|
||||
+++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100
|
||||
@@ -7,6 +7,18 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
+ * DOC: Station handling
|
||||
+ *
|
||||
+ * Stations are added per interface, but a special case exists with VLAN
|
||||
+ * interfaces. When a station is bound to an AP interface, it may be moved
|
||||
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
|
||||
+ * The station is still assumed to belong to the AP interface it was added
|
||||
+ * to.
|
||||
+ *
|
||||
+ * TODO: need more info?
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
* enum nl80211_commands - supported nl80211 commands
|
||||
*
|
||||
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
|
||||
@@ -56,6 +68,16 @@
|
||||
* parameters are like for %NL80211_CMD_SET_BEACON.
|
||||
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
|
||||
*
|
||||
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
|
||||
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
|
||||
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
|
||||
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
|
||||
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
|
||||
+ * the interface identified by %NL80211_ATTR_IFINDEX.
|
||||
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
|
||||
+ * or, if no MAC address given, all stations, on the interface identified
|
||||
+ * by %NL80211_ATTR_IFINDEX.
|
||||
+ *
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -83,6 +105,11 @@ enum nl80211_commands {
|
||||
NL80211_CMD_NEW_BEACON,
|
||||
NL80211_CMD_DEL_BEACON,
|
||||
|
||||
+ NL80211_CMD_GET_STATION,
|
||||
+ NL80211_CMD_SET_STATION,
|
||||
+ NL80211_CMD_NEW_STATION,
|
||||
+ NL80211_CMD_DEL_STATION,
|
||||
+
|
||||
/* add commands here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@@ -120,6 +147,17 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
|
||||
* @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
|
||||
*
|
||||
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
|
||||
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
|
||||
+ * &enum nl80211_sta_flags.
|
||||
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
|
||||
+ * IEEE 802.11 7.3.1.6 (u16).
|
||||
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
|
||||
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
|
||||
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
|
||||
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
|
||||
+ * to, or the AP interface the station was originally added to to.
|
||||
+ *
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -147,12 +185,20 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_BEACON_HEAD,
|
||||
NL80211_ATTR_BEACON_TAIL,
|
||||
|
||||
+ NL80211_ATTR_STA_AID,
|
||||
+ NL80211_ATTR_STA_FLAGS,
|
||||
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
|
||||
+ NL80211_ATTR_STA_SUPPORTED_RATES,
|
||||
+ NL80211_ATTR_STA_VLAN,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
+#define NL80211_MAX_SUPP_RATES 32
|
||||
+
|
||||
/**
|
||||
* enum nl80211_iftype - (virtual) interface types
|
||||
*
|
||||
@@ -184,4 +230,26 @@ enum nl80211_iftype {
|
||||
NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * enum nl80211_sta_flags - station flags
|
||||
+ *
|
||||
+ * Station flags. When a station is added to an AP interface, it is
|
||||
+ * assumed to be already associated (and hence authenticated.)
|
||||
+ *
|
||||
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
|
||||
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
|
||||
+ * with short barker preamble
|
||||
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
|
||||
+ */
|
||||
+enum nl80211_sta_flags {
|
||||
+ __NL80211_STA_FLAG_INVALID,
|
||||
+ NL80211_STA_FLAG_AUTHORIZED,
|
||||
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
|
||||
+ NL80211_STA_FLAG_WME,
|
||||
+
|
||||
+ /* keep last */
|
||||
+ __NL80211_STA_FLAG_AFTER_LAST,
|
||||
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
|
||||
+};
|
||||
+
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
--- everything.orig/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100
|
||||
+++ everything/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100
|
||||
@@ -89,6 +89,47 @@ struct beacon_parameters {
|
||||
int head_len, tail_len;
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * enum station_flags - station flags
|
||||
+ *
|
||||
+ * Station capability flags. Note that these must be the bits
|
||||
+ * according to the nl80211 flags.
|
||||
+ *
|
||||
+ * @STATION_FLAG_CHANGED: station flags were changed
|
||||
+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
|
||||
+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
|
||||
+ * with short preambles
|
||||
+ * @STATION_FLAG_WME: station is WME/QoS capable
|
||||
+ */
|
||||
+enum station_flags {
|
||||
+ STATION_FLAG_CHANGED = 1<<0,
|
||||
+ STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
|
||||
+ STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
|
||||
+ STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct station_parameters - station parameters
|
||||
+ *
|
||||
+ * Used to change and create a new station.
|
||||
+ *
|
||||
+ * @vlan: vlan interface station should belong to
|
||||
+ * @supported_rates: supported rates in IEEE 802.11 format
|
||||
+ * (or NULL for no change)
|
||||
+ * @supported_rates_len: number of supported rates
|
||||
+ * @station_flags: station flags (see &enum station_flags)
|
||||
+ * @listen_interval: listen interval or -1 for no change
|
||||
+ * @aid: AID or zero for no change
|
||||
+ */
|
||||
+struct station_parameters {
|
||||
+ u8 *supported_rates;
|
||||
+ struct net_device *vlan;
|
||||
+ u32 station_flags;
|
||||
+ int listen_interval;
|
||||
+ u16 aid;
|
||||
+ u8 supported_rates_len;
|
||||
+};
|
||||
+
|
||||
/* from net/wireless.h */
|
||||
struct wiphy;
|
||||
|
||||
@@ -130,6 +171,12 @@ struct wiphy;
|
||||
* interface. This should reject the call when no beacon has been
|
||||
* configured.
|
||||
* @del_beacon: Remove beacon configuration and stop sending the beacon.
|
||||
+ *
|
||||
+ * @add_station: Add a new station.
|
||||
+ *
|
||||
+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
|
||||
+ *
|
||||
+ * @change_station: Modify a given station.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
|
||||
@@ -155,6 +202,13 @@ struct cfg80211_ops {
|
||||
int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct beacon_parameters *info);
|
||||
int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
|
||||
+
|
||||
+ int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ u8 *mac, struct station_parameters *params);
|
||||
+ int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ u8 *mac);
|
||||
+ int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
|
||||
+ u8 *mac, struct station_parameters *params);
|
||||
};
|
||||
|
||||
#endif /* __NET_CFG80211_H */
|
||||
--- everything.orig/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100
|
||||
+++ everything/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100
|
||||
@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
|
||||
.len = IEEE80211_MAX_DATA_LEN },
|
||||
[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_MAX_DATA_LEN },
|
||||
+ [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
|
||||
+ [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
|
||||
+ [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
|
||||
+ [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
|
||||
+ .len = NL80211_MAX_SUPP_RATES },
|
||||
+ [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* message building helper */
|
||||
@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
|
||||
return err;
|
||||
}
|
||||
|
||||
+static
|
||||
+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
|
||||
+ [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
|
||||
+ [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
|
||||
+ [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
|
||||
+};
|
||||
+
|
||||
+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
|
||||
+{
|
||||
+ struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
|
||||
+ int flag;
|
||||
+
|
||||
+ *staflags = 0;
|
||||
+
|
||||
+ if (!nla)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
|
||||
+ nla, sta_flags_policy))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ *staflags = STATION_FLAG_CHANGED;
|
||||
+
|
||||
+ for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
|
||||
+ if (flags[flag])
|
||||
+ *staflags |= (1<<flag);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Get vlan interface making sure it is on the right wiphy.
|
||||
+ */
|
||||
+static int get_vlan(struct nlattr *vlanattr,
|
||||
+ struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device **vlan)
|
||||
+{
|
||||
+ *vlan = NULL;
|
||||
+
|
||||
+ if (vlanattr) {
|
||||
+ *vlan = dev_get_by_index(nla_get_u32(vlanattr));
|
||||
+ if (!*vlan)
|
||||
+ return -ENODEV;
|
||||
+ if (!(*vlan)->ieee80211_ptr)
|
||||
+ return -EINVAL;
|
||||
+ if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ struct station_parameters params;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+
|
||||
+ memset(¶ms, 0, sizeof(params));
|
||||
+
|
||||
+ params.listen_interval = -1;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_STA_AID])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_MAC])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
|
||||
+ params.supported_rates =
|
||||
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
+ params.supported_rates_len =
|
||||
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
+ }
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
+ params.listen_interval =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
+
|
||||
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
||||
+ ¶ms.station_flags))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!drv->ops->change_station) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ if (params.vlan)
|
||||
+ dev_put(params.vlan);
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ struct station_parameters params;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+
|
||||
+ memset(¶ms, 0, sizeof(params));
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_MAC])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_STA_AID])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+ params.supported_rates =
|
||||
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
+ params.supported_rates_len =
|
||||
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
+ params.listen_interval =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
+ params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
||||
+
|
||||
+ if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
||||
+ ¶ms.station_flags))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!drv->ops->add_station) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ if (params.vlan)
|
||||
+ dev_put(params.vlan);
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *drv;
|
||||
+ int err;
|
||||
+ struct net_device *dev;
|
||||
+ u8 *mac_addr = NULL;
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_MAC])
|
||||
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
+
|
||||
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!drv->ops->del_station) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ out:
|
||||
+ cfg80211_put_dev(drv);
|
||||
+ dev_put(dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static struct genl_ops nl80211_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
@@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = nl80211_del_beacon,
|
||||
},
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_GET_STATION,
|
||||
+ .doit = nl80211_get_station,
|
||||
+ /* TODO: implement dumpit */
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_SET_STATION,
|
||||
+ .doit = nl80211_set_station,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_NEW_STATION,
|
||||
+ .doit = nl80211_new_station,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
+ {
|
||||
+ .cmd = NL80211_CMD_DEL_STATION,
|
||||
+ .doit = nl80211_del_station,
|
||||
+ .policy = nl80211_policy,
|
||||
+ .flags = GENL_ADMIN_PERM,
|
||||
+ },
|
||||
};
|
||||
|
||||
/* multicast groups */
|
|
@ -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,
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
|
@ -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,
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
u32* iv32, u16* iv16);
|
||||
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
||||
u32 *iv32, u16 *iv16);
|
||||
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*set_retry_limit)(struct ieee80211_hw *hw,
|
||||
u32 short_retry, u32 long_retr);
|
||||
void (*sta_notify)(struct ieee80211_hw *hw, int if_id,
|
||||
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd, const u8 *addr);
|
||||
void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes,
|
||||
int cts_protection, int preamble);
|
||||
int (*conf_tx)(struct ieee80211_hw *hw, int queue,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
int (*get_tx_stats)(struct ieee80211_hw *hw,
|
||||
|
@ -1058,6 +1046,10 @@ struct ieee80211_ops {
|
|||
struct sk_buff *skb,
|
||||
struct ieee80211_tx_control *control);
|
||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||
int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
|
||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
const u8 *addr, u16 tid, u16 *ssn);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1089,6 +1081,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw);
|
|||
extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
|
||||
extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
|
||||
extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
|
||||
extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
|
||||
#endif
|
||||
/**
|
||||
* ieee80211_get_tx_led_name - get name of TX LED
|
||||
|
@ -1128,6 +1121,16 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_get_assoc_led_name - get name of association LED
|
||||
*
|
||||
* mac80211 creates a association LED trigger for each wireless hardware
|
||||
* that can be used to drive LEDs if your driver registers a LED device.
|
||||
* This function returns the name (or %NULL if not configured for LEDs)
|
||||
* of the trigger so you can automatically link the LED device.
|
||||
*
|
||||
* @hw: the hardware to get the LED trigger name for
|
||||
*/
|
||||
static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
|
@ -1137,10 +1140,24 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Register a new hardware PHYMODE capability to the stack. */
|
||||
int ieee80211_register_hwmode(struct ieee80211_hw *hw,
|
||||
struct ieee80211_hw_mode *mode);
|
||||
/**
|
||||
* ieee80211_get_radio_led_name - get name of radio LED
|
||||
*
|
||||
* mac80211 creates a radio change LED trigger for each wireless hardware
|
||||
* that can be used to drive LEDs if your driver registers a LED device.
|
||||
* This function returns the name (or %NULL if not configured for LEDs)
|
||||
* of the trigger so you can automatically link the LED device.
|
||||
*
|
||||
* @hw: the hardware to get the LED trigger name for
|
||||
*/
|
||||
static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
return __ieee80211_get_radio_led_name(hw);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_unregister_hw - Unregister a hardware device
|
||||
|
@ -1226,7 +1243,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
|
|||
/**
|
||||
* ieee80211_beacon_get - beacon generation function
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @control: will be filled with information needed to send this beacon.
|
||||
*
|
||||
* If the beacon frames are generated by the host system (i.e., not in
|
||||
|
@ -1237,13 +1254,13 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
|
|||
* is responsible of freeing it.
|
||||
*/
|
||||
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
int if_id,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_tx_control *control);
|
||||
|
||||
/**
|
||||
* ieee80211_rts_get - RTS frame generation function
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @frame: pointer to the frame that is going to be protected by the RTS.
|
||||
* @frame_len: the frame length (in octets).
|
||||
* @frame_txctl: &struct ieee80211_tx_control of the frame.
|
||||
|
@ -1254,7 +1271,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
* the next RTS frame from the 802.11 code. The low-level is responsible
|
||||
* for calling this function before and RTS frame is needed.
|
||||
*/
|
||||
void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
|
||||
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
const void *frame, size_t frame_len,
|
||||
const struct ieee80211_tx_control *frame_txctl,
|
||||
struct ieee80211_rts *rts);
|
||||
|
@ -1262,7 +1279,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
|
|||
/**
|
||||
* ieee80211_rts_duration - Get the duration field for an RTS frame
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @frame_len: the length of the frame that is going to be protected by the RTS.
|
||||
* @frame_txctl: &struct ieee80211_tx_control of the frame.
|
||||
*
|
||||
|
@ -1270,14 +1287,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
|
|||
* the duration field, the low-level driver uses this function to receive
|
||||
* the duration field value in little-endian byteorder.
|
||||
*/
|
||||
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
|
||||
size_t frame_len,
|
||||
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, size_t frame_len,
|
||||
const struct ieee80211_tx_control *frame_txctl);
|
||||
|
||||
/**
|
||||
* ieee80211_ctstoself_get - CTS-to-self frame generation function
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @frame: pointer to the frame that is going to be protected by the CTS-to-self.
|
||||
* @frame_len: the frame length (in octets).
|
||||
* @frame_txctl: &struct ieee80211_tx_control of the frame.
|
||||
|
@ -1288,7 +1305,8 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
|
|||
* the next CTS-to-self frame from the 802.11 code. The low-level is responsible
|
||||
* for calling this function before and CTS-to-self frame is needed.
|
||||
*/
|
||||
void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
|
||||
void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const void *frame, size_t frame_len,
|
||||
const struct ieee80211_tx_control *frame_txctl,
|
||||
struct ieee80211_cts *cts);
|
||||
|
@ -1296,7 +1314,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
|
|||
/**
|
||||
* ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
|
||||
* @frame_txctl: &struct ieee80211_tx_control of the frame.
|
||||
*
|
||||
|
@ -1304,28 +1322,30 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
|
|||
* the duration field, the low-level driver uses this function to receive
|
||||
* the duration field value in little-endian byteorder.
|
||||
*/
|
||||
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
|
||||
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
size_t frame_len,
|
||||
const struct ieee80211_tx_control *frame_txctl);
|
||||
|
||||
/**
|
||||
* ieee80211_generic_frame_duration - Calculate the duration field for a frame
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @frame_len: the length of the frame.
|
||||
* @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
|
||||
* @rate: the rate at which the frame is going to be transmitted.
|
||||
*
|
||||
* Calculate the duration field of some generic frame, given its
|
||||
* length and transmission rate (in 100kbps).
|
||||
*/
|
||||
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
|
||||
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
size_t frame_len,
|
||||
int rate);
|
||||
struct ieee80211_rate *rate);
|
||||
|
||||
/**
|
||||
* ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @if_id: interface ID from &struct ieee80211_if_init_conf.
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
|
||||
* @control: will be filled with information needed to send returned frame.
|
||||
*
|
||||
* Function for accessing buffered broadcast and multicast frames. If
|
||||
|
@ -1344,7 +1364,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
|
|||
* use common code for all beacons.
|
||||
*/
|
||||
struct sk_buff *
|
||||
ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
|
||||
ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_tx_control *control);
|
||||
|
||||
/**
|
||||
|
@ -1422,8 +1442,96 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
|
|||
*/
|
||||
void ieee80211_scan_completed(struct ieee80211_hw *hw);
|
||||
|
||||
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
|
||||
((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
|
||||
/**
|
||||
* ieee80211_iterate_active_interfaces - iterate active interfaces
|
||||
*
|
||||
* This function iterates over the interfaces associated with a given
|
||||
* hardware that are currently active and calls the callback for them.
|
||||
*
|
||||
* @hw: the hardware struct of which the interfaces should be iterated over
|
||||
* @iterator: the iterator function to call, cannot sleep
|
||||
* @data: first argument of the iterator function
|
||||
*/
|
||||
void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif),
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient
|
||||
* @tid: the TID to BA on.
|
||||
* @return: success if addBA request was sent, failure otherwise
|
||||
*
|
||||
* Although mac80211/low level driver/user space application can estimate
|
||||
* the need to start aggregation on a certain RA/TID, the session level
|
||||
* will be managed by the mac80211.
|
||||
*/
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session.
|
||||
*/
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session.
|
||||
* This version of the function is irq safe.
|
||||
*/
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient
|
||||
* @tid: the TID to stop BA.
|
||||
* @initiator: if indicates initiator DELBA frame will be sent.
|
||||
* @return: error if no sta with matching da found, success otherwise
|
||||
*
|
||||
* Although mac80211/low level driver/user space application can estimate
|
||||
* the need to stop aggregation on a certain RA/TID, the session level
|
||||
* will be managed by the mac80211.
|
||||
*/
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||
u8 *ra, u16 tid,
|
||||
enum ieee80211_back_parties initiator);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the desired TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session tear down.
|
||||
*/
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the desired TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session tear down.
|
||||
* This version of the function is irq safe.
|
||||
*/
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
u16 tid);
|
||||
|
||||
#endif /* MAC80211_H */
|
||||
|
|
|
@ -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 */
|
|
@ -1,6 +1,5 @@
|
|||
config MAC80211
|
||||
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
|
||||
depends on EXPERIMENTAL
|
||||
select CRYPTO
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_ARC4
|
||||
|
@ -10,15 +9,84 @@ config MAC80211
|
|||
select CFG80211
|
||||
select NET_SCH_FIFO
|
||||
---help---
|
||||
This option enables the hardware independent IEEE 802.11
|
||||
networking stack.
|
||||
This option enables the hardware independent IEEE 802.11
|
||||
networking stack.
|
||||
|
||||
menu "Rate control algorithm selection"
|
||||
depends on MAC80211 != n
|
||||
|
||||
choice
|
||||
prompt "Default rate control algorithm"
|
||||
default MAC80211_RC_DEFAULT_PID
|
||||
---help---
|
||||
This option selects the default rate control algorithm
|
||||
mac80211 will use. Note that this default can still be
|
||||
overriden through the ieee80211_default_rc_algo module
|
||||
parameter if different algorithms are available.
|
||||
|
||||
config MAC80211_RC_DEFAULT_PID
|
||||
bool "PID controller based rate control algorithm"
|
||||
select MAC80211_RC_PID
|
||||
---help---
|
||||
Select the PID controller based rate control as the
|
||||
default rate control algorithm. You should choose
|
||||
this unless you know what you are doing.
|
||||
|
||||
config MAC80211_RC_DEFAULT_SIMPLE
|
||||
bool "Simple rate control algorithm"
|
||||
select MAC80211_RC_SIMPLE
|
||||
---help---
|
||||
Select the simple rate control as the default rate
|
||||
control algorithm. Note that this is a non-responsive,
|
||||
dumb algorithm. You should choose the PID rate control
|
||||
instead.
|
||||
|
||||
config MAC80211_RC_DEFAULT_NONE
|
||||
bool "No default algorithm"
|
||||
depends on EMBEDDED
|
||||
help
|
||||
Selecting this option will select no default algorithm
|
||||
and allow you to not build any. Do not choose this
|
||||
option unless you know your driver comes with another
|
||||
suitable algorithm.
|
||||
endchoice
|
||||
|
||||
comment "Selecting 'y' for an algorithm will"
|
||||
comment "build the algorithm into mac80211."
|
||||
|
||||
config MAC80211_RC_DEFAULT
|
||||
string
|
||||
default "pid" if MAC80211_RC_DEFAULT_PID
|
||||
default "simple" if MAC80211_RC_DEFAULT_SIMPLE
|
||||
default ""
|
||||
|
||||
config MAC80211_RC_PID
|
||||
tristate "PID controller based rate control algorithm"
|
||||
---help---
|
||||
This option enables a TX rate control algorithm for
|
||||
mac80211 that uses a PID controller to select the TX
|
||||
rate.
|
||||
|
||||
Say Y or M unless you're sure you want to use a
|
||||
different rate control algorithm.
|
||||
|
||||
config MAC80211_RC_SIMPLE
|
||||
tristate "Simple rate control algorithm (DEPRECATED)"
|
||||
---help---
|
||||
This option enables a very simple, non-responsive TX
|
||||
rate control algorithm. This algorithm is deprecated
|
||||
and will be removed from the kernel in the near future.
|
||||
It has been replaced by the PID algorithm.
|
||||
|
||||
Say N unless you know what you are doing.
|
||||
endmenu
|
||||
|
||||
config MAC80211_LEDS
|
||||
bool "Enable LED triggers"
|
||||
depends on MAC80211 && LEDS_TRIGGERS
|
||||
---help---
|
||||
This option enables a few LED triggers for different
|
||||
packet receive/transmit events.
|
||||
This option enables a few LED triggers for different
|
||||
packet receive/transmit events.
|
||||
|
||||
config MAC80211_DEBUGFS
|
||||
bool "Export mac80211 internals in DebugFS"
|
||||
|
@ -29,6 +97,18 @@ config MAC80211_DEBUGFS
|
|||
|
||||
Say N unless you know you need this.
|
||||
|
||||
config MAC80211_DEBUG_PACKET_ALIGNMENT
|
||||
bool "Enable packet alignment debugging"
|
||||
depends on MAC80211
|
||||
help
|
||||
This option is recommended for driver authors and strongly
|
||||
discouraged for everybody else, it will trigger a warning
|
||||
when a driver hands mac80211 a buffer that is aligned in
|
||||
a way that will cause problems with the IP stack on some
|
||||
architectures.
|
||||
|
||||
Say N unless you're writing a mac80211 based driver.
|
||||
|
||||
config MAC80211_DEBUG
|
||||
bool "Enable debugging output"
|
||||
depends on MAC80211
|
||||
|
@ -39,6 +119,16 @@ config MAC80211_DEBUG
|
|||
If you are not trying to debug or develop the ieee80211
|
||||
subsystem, you most likely want to say N here.
|
||||
|
||||
config MAC80211_HT_DEBUG
|
||||
bool "Enable HT debugging output"
|
||||
depends on MAC80211_DEBUG
|
||||
---help---
|
||||
This option enables 802.11n High Throughput features
|
||||
debug tracing output.
|
||||
|
||||
If you are not trying to debug of develop the ieee80211
|
||||
subsystem, you most likely want to say N here.
|
||||
|
||||
config MAC80211_VERBOSE_DEBUG
|
||||
bool "Verbose debugging output"
|
||||
depends on MAC80211_DEBUG
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
/*
|
||||
* mac80211 configuration hooks for cfg80211
|
||||
*
|
||||
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "cfg.h"
|
||||
#include "ieee80211_rate.h"
|
||||
|
||||
static enum ieee80211_if_types
|
||||
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
|
||||
|
@ -30,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
|
|||
}
|
||||
|
||||
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
||||
enum nl80211_iftype type)
|
||||
enum nl80211_iftype type, u32 *flags)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
enum ieee80211_if_types itype;
|
||||
struct net_device *dev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int err;
|
||||
|
||||
if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
|
||||
return -ENODEV;
|
||||
|
@ -42,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
|||
if (itype == IEEE80211_IF_TYPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
return ieee80211_if_add(local->mdev, name, NULL, itype);
|
||||
err = ieee80211_if_add(local->mdev, name, &dev, itype);
|
||||
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
|
||||
return err;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
sdata->u.mntr_flags = *flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
|
||||
|
@ -55,7 +68,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
|
|||
return -ENODEV;
|
||||
|
||||
/* we're under RTNL */
|
||||
dev = __dev_get_by_index(ifindex);
|
||||
dev = __dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
|
@ -65,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
|
|||
}
|
||||
|
||||
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
||||
enum nl80211_iftype type)
|
||||
enum nl80211_iftype type, u32 *flags)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
|
@ -76,7 +89,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
|||
return -ENODEV;
|
||||
|
||||
/* we're under RTNL */
|
||||
dev = __dev_get_by_index(ifindex);
|
||||
dev = __dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -89,12 +102,551 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
|
|||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_VLAN)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ieee80211_if_reinit(dev);
|
||||
ieee80211_if_set_type(dev, itype);
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
|
||||
return 0;
|
||||
|
||||
sdata->u.mntr_flags = *flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta = NULL;
|
||||
enum ieee80211_key_alg alg;
|
||||
int ret;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
switch (params->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
alg = ALG_WEP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
alg = ALG_TKIP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
alg = ALG_CCMP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
if (!sta)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
|
||||
params->key_len, params->key))
|
||||
ret = -ENOMEM;
|
||||
|
||||
if (sta)
|
||||
sta_info_put(sta);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, u8 *mac_addr)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
if (!sta)
|
||||
return -ENOENT;
|
||||
|
||||
ret = 0;
|
||||
if (sta->key)
|
||||
ieee80211_key_free(sta->key);
|
||||
else
|
||||
ret = -ENOENT;
|
||||
|
||||
sta_info_put(sta);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!sdata->keys[key_idx])
|
||||
return -ENOENT;
|
||||
|
||||
ieee80211_key_free(sdata->keys[key_idx]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, u8 *mac_addr, void *cookie,
|
||||
void (*callback)(void *cookie,
|
||||
struct key_params *params))
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta = NULL;
|
||||
u8 seq[6] = {0};
|
||||
struct key_params params;
|
||||
struct ieee80211_key *key;
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (mac_addr) {
|
||||
sta = sta_info_get(sdata->local, mac_addr);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
key = sta->key;
|
||||
} else
|
||||
key = sdata->keys[key_idx];
|
||||
|
||||
if (!key)
|
||||
goto out;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
switch (key->conf.alg) {
|
||||
case ALG_TKIP:
|
||||
params.cipher = WLAN_CIPHER_SUITE_TKIP;
|
||||
|
||||
iv32 = key->u.tkip.iv32;
|
||||
iv16 = key->u.tkip.iv16;
|
||||
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
sdata->local->ops->get_tkip_seq)
|
||||
sdata->local->ops->get_tkip_seq(
|
||||
local_to_hw(sdata->local),
|
||||
key->conf.hw_key_idx,
|
||||
&iv32, &iv16);
|
||||
|
||||
seq[0] = iv16 & 0xff;
|
||||
seq[1] = (iv16 >> 8) & 0xff;
|
||||
seq[2] = iv32 & 0xff;
|
||||
seq[3] = (iv32 >> 8) & 0xff;
|
||||
seq[4] = (iv32 >> 16) & 0xff;
|
||||
seq[5] = (iv32 >> 24) & 0xff;
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
params.cipher = WLAN_CIPHER_SUITE_CCMP;
|
||||
seq[0] = key->u.ccmp.tx_pn[5];
|
||||
seq[1] = key->u.ccmp.tx_pn[4];
|
||||
seq[2] = key->u.ccmp.tx_pn[3];
|
||||
seq[3] = key->u.ccmp.tx_pn[2];
|
||||
seq[4] = key->u.ccmp.tx_pn[1];
|
||||
seq[5] = key->u.ccmp.tx_pn[0];
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case ALG_WEP:
|
||||
if (key->conf.keylen == 5)
|
||||
params.cipher = WLAN_CIPHER_SUITE_WEP40;
|
||||
else
|
||||
params.cipher = WLAN_CIPHER_SUITE_WEP104;
|
||||
break;
|
||||
}
|
||||
|
||||
params.key = key->conf.key;
|
||||
params.key_len = key->conf.keylen;
|
||||
|
||||
callback(cookie, ¶ms);
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (sta)
|
||||
sta_info_put(sta);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ieee80211_config_default_key(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 key_idx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
ieee80211_set_default_key(sdata, key_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *mac, struct station_stats *stats)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = sta_info_get(local, mac);
|
||||
if (!sta)
|
||||
return -ENOENT;
|
||||
|
||||
/* XXX: verify sta->dev == dev */
|
||||
|
||||
stats->filled = STATION_STAT_INACTIVE_TIME |
|
||||
STATION_STAT_RX_BYTES |
|
||||
STATION_STAT_TX_BYTES;
|
||||
|
||||
stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
|
||||
stats->rx_bytes = sta->rx_bytes;
|
||||
stats->tx_bytes = sta->tx_bytes;
|
||||
|
||||
sta_info_put(sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles both adding a beacon and setting new beacon info
|
||||
*/
|
||||
static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_parameters *params)
|
||||
{
|
||||
struct beacon_data *new, *old;
|
||||
int new_head_len, new_tail_len;
|
||||
int size;
|
||||
int err = -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
/* head must not be zero-length */
|
||||
if (params->head && !params->head_len)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* This is a kludge. beacon interval should really be part
|
||||
* of the beacon information.
|
||||
*/
|
||||
if (params->interval) {
|
||||
sdata->local->hw.conf.beacon_int = params->interval;
|
||||
if (ieee80211_hw_config(sdata->local))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* We updated some parameter so if below bails out
|
||||
* it's not an error.
|
||||
*/
|
||||
err = 0;
|
||||
}
|
||||
|
||||
/* Need to have a beacon head if we don't have one yet */
|
||||
if (!params->head && !old)
|
||||
return err;
|
||||
|
||||
/* sorry, no way to start beaconing without dtim period */
|
||||
if (!params->dtim_period && !old)
|
||||
return err;
|
||||
|
||||
/* new or old head? */
|
||||
if (params->head)
|
||||
new_head_len = params->head_len;
|
||||
else
|
||||
new_head_len = old->head_len;
|
||||
|
||||
/* new or old tail? */
|
||||
if (params->tail || !old)
|
||||
/* params->tail_len will be zero for !params->tail */
|
||||
new_tail_len = params->tail_len;
|
||||
else
|
||||
new_tail_len = old->tail_len;
|
||||
|
||||
size = sizeof(*new) + new_head_len + new_tail_len;
|
||||
|
||||
new = kzalloc(size, GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
/* start filling the new info now */
|
||||
|
||||
/* new or old dtim period? */
|
||||
if (params->dtim_period)
|
||||
new->dtim_period = params->dtim_period;
|
||||
else
|
||||
new->dtim_period = old->dtim_period;
|
||||
|
||||
/*
|
||||
* pointers go into the block we allocated,
|
||||
* memory is | beacon_data | head | tail |
|
||||
*/
|
||||
new->head = ((u8 *) new) + sizeof(*new);
|
||||
new->tail = new->head + new_head_len;
|
||||
new->head_len = new_head_len;
|
||||
new->tail_len = new_tail_len;
|
||||
|
||||
/* copy in head */
|
||||
if (params->head)
|
||||
memcpy(new->head, params->head, new_head_len);
|
||||
else
|
||||
memcpy(new->head, old->head, new_head_len);
|
||||
|
||||
/* copy in optional tail */
|
||||
if (params->tail)
|
||||
memcpy(new->tail, params->tail, new_tail_len);
|
||||
else
|
||||
if (old)
|
||||
memcpy(new->tail, old->tail, new_tail_len);
|
||||
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, new);
|
||||
|
||||
synchronize_rcu();
|
||||
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config_beacon(sdata->dev);
|
||||
}
|
||||
|
||||
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct beacon_parameters *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct beacon_data *old;
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (old)
|
||||
return -EALREADY;
|
||||
|
||||
return ieee80211_config_beacon(sdata, params);
|
||||
}
|
||||
|
||||
static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct beacon_parameters *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct beacon_data *old;
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (!old)
|
||||
return -ENOENT;
|
||||
|
||||
return ieee80211_config_beacon(sdata, params);
|
||||
}
|
||||
|
||||
static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct beacon_data *old;
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
old = sdata->u.ap.beacon;
|
||||
|
||||
if (!old)
|
||||
return -ENOENT;
|
||||
|
||||
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(old);
|
||||
|
||||
return ieee80211_if_config_beacon(dev);
|
||||
}
|
||||
|
||||
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
|
||||
struct iapp_layer2_update {
|
||||
u8 da[ETH_ALEN]; /* broadcast */
|
||||
u8 sa[ETH_ALEN]; /* STA addr */
|
||||
__be16 len; /* 6 */
|
||||
u8 dsap; /* 0 */
|
||||
u8 ssap; /* 0 */
|
||||
u8 control;
|
||||
u8 xid_info[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static void ieee80211_send_layer2_update(struct sta_info *sta)
|
||||
{
|
||||
struct iapp_layer2_update *msg;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Send Level 2 Update Frame to update forwarding tables in layer 2
|
||||
* bridge devices */
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*msg));
|
||||
if (!skb)
|
||||
return;
|
||||
msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
|
||||
|
||||
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
|
||||
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
|
||||
|
||||
memset(msg->da, 0xff, ETH_ALEN);
|
||||
memcpy(msg->sa, sta->addr, ETH_ALEN);
|
||||
msg->len = htons(6);
|
||||
msg->dsap = 0;
|
||||
msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
|
||||
msg->control = 0xaf; /* XID response lsb.1111F101.
|
||||
* F=0 (no poll command; unsolicited frame) */
|
||||
msg->xid_info[0] = 0x81; /* XID format identifier */
|
||||
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
|
||||
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
|
||||
|
||||
skb->dev = sta->dev;
|
||||
skb->protocol = eth_type_trans(skb, sta->dev);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
static void sta_apply_parameters(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
u32 rates;
|
||||
int i, j;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
if (params->station_flags & STATION_FLAG_CHANGED) {
|
||||
sta->flags &= ~WLAN_STA_AUTHORIZED;
|
||||
if (params->station_flags & STATION_FLAG_AUTHORIZED)
|
||||
sta->flags |= WLAN_STA_AUTHORIZED;
|
||||
|
||||
sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
|
||||
if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
|
||||
sta->flags |= WLAN_STA_SHORT_PREAMBLE;
|
||||
|
||||
sta->flags &= ~WLAN_STA_WME;
|
||||
if (params->station_flags & STATION_FLAG_WME)
|
||||
sta->flags |= WLAN_STA_WME;
|
||||
}
|
||||
|
||||
if (params->aid) {
|
||||
sta->aid = params->aid;
|
||||
if (sta->aid > IEEE80211_MAX_AID)
|
||||
sta->aid = 0; /* XXX: should this be an error? */
|
||||
}
|
||||
|
||||
if (params->listen_interval >= 0)
|
||||
sta->listen_interval = params->listen_interval;
|
||||
|
||||
if (params->supported_rates) {
|
||||
rates = 0;
|
||||
sband = local->hw.wiphy->bands[local->oper_channel->band];
|
||||
|
||||
for (i = 0; i < params->supported_rates_len; i++) {
|
||||
int rate = (params->supported_rates[i] & 0x7f) * 5;
|
||||
for (j = 0; j < sband->n_bitrates; j++) {
|
||||
if (sband->bitrates[j].bitrate == rate)
|
||||
rates |= BIT(j);
|
||||
}
|
||||
}
|
||||
sta->supp_rates[local->oper_channel->band] = rates;
|
||||
}
|
||||
}
|
||||
|
||||
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *mac, struct station_parameters *params)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
/* Prevent a race with changing the rate control algorithm */
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
if (sta) {
|
||||
sta_info_put(sta);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (params->vlan) {
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
|
||||
sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EINVAL;
|
||||
} else
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sta = sta_info_add(local, dev, mac, GFP_KERNEL);
|
||||
if (!sta)
|
||||
return -ENOMEM;
|
||||
|
||||
sta->dev = sdata->dev;
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_AP)
|
||||
ieee80211_send_layer2_update(sta);
|
||||
|
||||
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
|
||||
sta_apply_parameters(local, sta, params);
|
||||
|
||||
rate_control_rate_init(sta, local);
|
||||
|
||||
sta_info_put(sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *mac)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
|
||||
if (mac) {
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
if (!sta)
|
||||
return -ENOENT;
|
||||
|
||||
sta_info_free(sta);
|
||||
sta_info_put(sta);
|
||||
} else
|
||||
sta_info_flush(local, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 *mac,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *vlansdata;
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
if (!sta)
|
||||
return -ENOENT;
|
||||
|
||||
if (params->vlan && params->vlan != sta->dev) {
|
||||
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
|
||||
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
|
||||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
sta->dev = params->vlan;
|
||||
ieee80211_send_layer2_update(sta);
|
||||
}
|
||||
|
||||
sta_apply_parameters(local, sta, params);
|
||||
|
||||
sta_info_put(sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -102,4 +654,15 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
.change_virtual_intf = ieee80211_change_iface,
|
||||
.add_key = ieee80211_add_key,
|
||||
.del_key = ieee80211_del_key,
|
||||
.get_key = ieee80211_get_key,
|
||||
.set_default_key = ieee80211_config_default_key,
|
||||
.add_beacon = ieee80211_add_beacon,
|
||||
.set_beacon = ieee80211_set_beacon,
|
||||
.del_beacon = ieee80211_del_beacon,
|
||||
.add_station = ieee80211_add_station,
|
||||
.del_station = ieee80211_del_station,
|
||||
.change_station = ieee80211_change_station,
|
||||
.get_station = ieee80211_get_station,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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 */
|
|
@ -37,8 +37,6 @@
|
|||
|
||||
struct ieee80211_local;
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
#define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
|
||||
|
||||
/* Maximum number of broadcast/multicast frames to buffer when some of the
|
||||
|
@ -81,8 +79,7 @@ struct ieee80211_sta_bss {
|
|||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t ssid_len;
|
||||
u16 capability; /* host byte order */
|
||||
int hw_mode;
|
||||
int channel;
|
||||
enum ieee80211_band band;
|
||||
int freq;
|
||||
int rssi, signal, noise;
|
||||
u8 *wpa_ie;
|
||||
|
@ -91,6 +88,8 @@ struct ieee80211_sta_bss {
|
|||
size_t rsn_ie_len;
|
||||
u8 *wmm_ie;
|
||||
size_t wmm_ie_len;
|
||||
u8 *ht_ie;
|
||||
size_t ht_ie_len;
|
||||
#define IEEE80211_MAX_SUPP_RATES 32
|
||||
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
|
||||
size_t supp_rates_len;
|
||||
|
@ -109,9 +108,17 @@ struct ieee80211_sta_bss {
|
|||
};
|
||||
|
||||
|
||||
typedef enum {
|
||||
TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
|
||||
} ieee80211_txrx_result;
|
||||
typedef unsigned __bitwise__ ieee80211_tx_result;
|
||||
#define TX_CONTINUE ((__force ieee80211_tx_result) 0u)
|
||||
#define TX_DROP ((__force ieee80211_tx_result) 1u)
|
||||
#define TX_QUEUED ((__force ieee80211_tx_result) 2u)
|
||||
|
||||
typedef unsigned __bitwise__ ieee80211_rx_result;
|
||||
#define RX_CONTINUE ((__force ieee80211_rx_result) 0u)
|
||||
#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u)
|
||||
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
|
||||
#define RX_QUEUED ((__force ieee80211_rx_result) 3u)
|
||||
|
||||
|
||||
/* flags used in struct ieee80211_txrx_data.flags */
|
||||
/* whether the MSDU was fragmented */
|
||||
|
@ -123,6 +130,8 @@ typedef enum {
|
|||
/* frame is destined to interface currently processed (incl. multicast frames) */
|
||||
#define IEEE80211_TXRXD_RXRA_MATCH BIT(5)
|
||||
#define IEEE80211_TXRXD_TX_INJECTED BIT(6)
|
||||
#define IEEE80211_TXRXD_RX_AMSDU BIT(7)
|
||||
#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8)
|
||||
struct ieee80211_txrx_data {
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
|
@ -135,13 +144,12 @@ struct ieee80211_txrx_data {
|
|||
union {
|
||||
struct {
|
||||
struct ieee80211_tx_control *control;
|
||||
struct ieee80211_hw_mode *mode;
|
||||
struct ieee80211_channel *channel;
|
||||
struct ieee80211_rate *rate;
|
||||
/* use this rate (if set) for last fragment; rate can
|
||||
* be set to lower rate for the first fragments, e.g.,
|
||||
* when using CTS protection with IEEE 802.11g. */
|
||||
struct ieee80211_rate *last_frag_rate;
|
||||
int last_frag_hwrate;
|
||||
|
||||
/* Extra fragments (in addition to the first fragment
|
||||
* in skb) */
|
||||
|
@ -150,6 +158,7 @@ struct ieee80211_txrx_data {
|
|||
} tx;
|
||||
struct {
|
||||
struct ieee80211_rx_status *status;
|
||||
struct ieee80211_rate *rate;
|
||||
int sent_ps_buffered;
|
||||
int queue;
|
||||
int load;
|
||||
|
@ -163,6 +172,8 @@ struct ieee80211_txrx_data {
|
|||
#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
|
||||
#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
|
||||
#define IEEE80211_TXPD_REQUEUE BIT(2)
|
||||
#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
|
||||
#define IEEE80211_TXPD_AMPDU BIT(4)
|
||||
/* Stored in sk_buff->cb */
|
||||
struct ieee80211_tx_packet_data {
|
||||
int ifindex;
|
||||
|
@ -176,21 +187,18 @@ struct ieee80211_tx_stored_packet {
|
|||
struct sk_buff *skb;
|
||||
int num_extra_frag;
|
||||
struct sk_buff **extra_frag;
|
||||
int last_frag_rateidx;
|
||||
int last_frag_hwrate;
|
||||
struct ieee80211_rate *last_frag_rate;
|
||||
unsigned int last_frag_rate_ctrl_probe;
|
||||
};
|
||||
|
||||
typedef ieee80211_txrx_result (*ieee80211_tx_handler)
|
||||
(struct ieee80211_txrx_data *tx);
|
||||
|
||||
typedef ieee80211_txrx_result (*ieee80211_rx_handler)
|
||||
(struct ieee80211_txrx_data *rx);
|
||||
struct beacon_data {
|
||||
u8 *head, *tail;
|
||||
int head_len, tail_len;
|
||||
int dtim_period;
|
||||
};
|
||||
|
||||
struct ieee80211_if_ap {
|
||||
u8 *beacon_head, *beacon_tail;
|
||||
int beacon_head_len, beacon_tail_len;
|
||||
struct beacon_data *beacon;
|
||||
|
||||
struct list_head vlans;
|
||||
|
||||
|
@ -203,7 +211,7 @@ struct ieee80211_if_ap {
|
|||
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
|
||||
atomic_t num_sta_ps; /* number of stations in PS mode */
|
||||
struct sk_buff_head ps_bc_buf;
|
||||
int dtim_period, dtim_count;
|
||||
int dtim_count;
|
||||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||
int num_beacons; /* number of TXed beacon frames for this BSS */
|
||||
|
@ -232,6 +240,7 @@ struct ieee80211_if_vlan {
|
|||
#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
|
||||
#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
|
||||
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
|
||||
#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
|
||||
struct ieee80211_if_sta {
|
||||
enum {
|
||||
IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
|
||||
|
@ -243,6 +252,8 @@ struct ieee80211_if_sta {
|
|||
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t ssid_len;
|
||||
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t scan_ssid_len;
|
||||
u16 aid;
|
||||
u16 ap_capab, capab;
|
||||
u8 *extra_ie; /* to be added to the end of AssocReq */
|
||||
|
@ -261,7 +272,6 @@ struct ieee80211_if_sta {
|
|||
unsigned long request;
|
||||
struct sk_buff_head skb_queue;
|
||||
|
||||
int key_management_enabled;
|
||||
unsigned long last_probe;
|
||||
|
||||
#define IEEE80211_AUTH_ALG_OPEN BIT(0)
|
||||
|
@ -273,7 +283,7 @@ struct ieee80211_if_sta {
|
|||
|
||||
unsigned long ibss_join_req;
|
||||
struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
|
||||
u32 supp_rates_bits;
|
||||
u32 supp_rates_bits[IEEE80211_NUM_BANDS];
|
||||
|
||||
int wmm_last_param_set;
|
||||
};
|
||||
|
@ -282,15 +292,10 @@ struct ieee80211_if_sta {
|
|||
/* flags used in struct ieee80211_sub_if_data.flags */
|
||||
#define IEEE80211_SDATA_ALLMULTI BIT(0)
|
||||
#define IEEE80211_SDATA_PROMISC BIT(1)
|
||||
#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */
|
||||
/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon
|
||||
* generator reports that there are no present stations that cannot support short
|
||||
* preambles */
|
||||
#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3)
|
||||
#define IEEE80211_SDATA_USERSPACE_MLME BIT(4)
|
||||
#define IEEE80211_SDATA_USERSPACE_MLME BIT(2)
|
||||
#define IEEE80211_SDATA_OPERATING_GMODE BIT(3)
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
enum ieee80211_if_types type;
|
||||
|
||||
struct wireless_dev wdev;
|
||||
|
||||
|
@ -303,11 +308,11 @@ struct ieee80211_sub_if_data {
|
|||
unsigned int flags;
|
||||
|
||||
int drop_unencrypted;
|
||||
int eapol; /* 0 = process EAPOL frames as normal data frames,
|
||||
* 1 = send EAPOL frames through wlan#ap to hostapd
|
||||
* (default) */
|
||||
int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
|
||||
* port */
|
||||
|
||||
/*
|
||||
* basic rates of this AP or the AP we're associated to
|
||||
*/
|
||||
u64 basic_rates;
|
||||
|
||||
u16 sequence;
|
||||
|
||||
|
@ -319,6 +324,15 @@ struct ieee80211_sub_if_data {
|
|||
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
|
||||
struct ieee80211_key *default_key;
|
||||
|
||||
/*
|
||||
* BSS configuration for this interface.
|
||||
*
|
||||
* FIXME: I feel bad putting this here when we already have a
|
||||
* bss pointer, but the bss pointer is just wrong when
|
||||
* you have multiple virtual STA mode interfaces...
|
||||
* This needs to be fixed.
|
||||
*/
|
||||
struct ieee80211_bss_conf bss_conf;
|
||||
struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
|
||||
|
||||
union {
|
||||
|
@ -326,6 +340,7 @@ struct ieee80211_sub_if_data {
|
|||
struct ieee80211_if_wds wds;
|
||||
struct ieee80211_if_vlan vlan;
|
||||
struct ieee80211_if_sta sta;
|
||||
u32 mntr_flags;
|
||||
} u;
|
||||
int channel_use;
|
||||
int channel_use_raw;
|
||||
|
@ -336,8 +351,6 @@ struct ieee80211_sub_if_data {
|
|||
struct {
|
||||
struct dentry *channel_use;
|
||||
struct dentry *drop_unencrypted;
|
||||
struct dentry *eapol;
|
||||
struct dentry *ieee8021_x;
|
||||
struct dentry *state;
|
||||
struct dentry *bssid;
|
||||
struct dentry *prev_bssid;
|
||||
|
@ -356,30 +369,21 @@ struct ieee80211_sub_if_data {
|
|||
struct {
|
||||
struct dentry *channel_use;
|
||||
struct dentry *drop_unencrypted;
|
||||
struct dentry *eapol;
|
||||
struct dentry *ieee8021_x;
|
||||
struct dentry *num_sta_ps;
|
||||
struct dentry *dtim_period;
|
||||
struct dentry *dtim_count;
|
||||
struct dentry *num_beacons;
|
||||
struct dentry *force_unicast_rateidx;
|
||||
struct dentry *max_ratectrl_rateidx;
|
||||
struct dentry *num_buffered_multicast;
|
||||
struct dentry *beacon_head_len;
|
||||
struct dentry *beacon_tail_len;
|
||||
} ap;
|
||||
struct {
|
||||
struct dentry *channel_use;
|
||||
struct dentry *drop_unencrypted;
|
||||
struct dentry *eapol;
|
||||
struct dentry *ieee8021_x;
|
||||
struct dentry *peer;
|
||||
} wds;
|
||||
struct {
|
||||
struct dentry *channel_use;
|
||||
struct dentry *drop_unencrypted;
|
||||
struct dentry *eapol;
|
||||
struct dentry *ieee8021_x;
|
||||
} vlan;
|
||||
struct {
|
||||
struct dentry *mode;
|
||||
|
@ -387,13 +391,23 @@ struct ieee80211_sub_if_data {
|
|||
struct dentry *default_key;
|
||||
} debugfs;
|
||||
#endif
|
||||
/* must be last, dynamically sized area in this! */
|
||||
struct ieee80211_vif vif;
|
||||
};
|
||||
|
||||
static inline
|
||||
struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
|
||||
{
|
||||
return container_of(p, struct ieee80211_sub_if_data, vif);
|
||||
}
|
||||
|
||||
#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
|
||||
|
||||
enum {
|
||||
IEEE80211_RX_MSG = 1,
|
||||
IEEE80211_TX_STATUS_MSG = 2,
|
||||
IEEE80211_DELBA_MSG = 3,
|
||||
IEEE80211_ADDBA_MSG = 4,
|
||||
};
|
||||
|
||||
struct ieee80211_local {
|
||||
|
@ -404,12 +418,11 @@ struct ieee80211_local {
|
|||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/* List of registered struct ieee80211_hw_mode */
|
||||
struct list_head modes_list;
|
||||
|
||||
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
|
||||
int open_count;
|
||||
int monitors;
|
||||
int monitors, cooked_mntrs;
|
||||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
|
||||
unsigned int filter_flags; /* FIF_* */
|
||||
struct iw_statistics wstats;
|
||||
u8 wstats_flags;
|
||||
|
@ -437,8 +450,8 @@ struct ieee80211_local {
|
|||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
struct timer_list sta_cleanup;
|
||||
|
||||
unsigned long state[NUM_TX_DATA_QUEUES];
|
||||
struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
|
||||
unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
|
||||
struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
|
||||
struct tasklet_struct tx_pending_tasklet;
|
||||
|
||||
/* number of interfaces with corresponding IFF_ flags */
|
||||
|
@ -446,11 +459,6 @@ struct ieee80211_local {
|
|||
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
|
||||
/* Supported and basic rate filters for different modes. These are
|
||||
* pointers to -1 terminated lists and rates in 100 kbps units. */
|
||||
int *supp_rates[NUM_IEEE80211_MODES];
|
||||
int *basic_rates[NUM_IEEE80211_MODES];
|
||||
|
||||
int rts_threshold;
|
||||
int fragmentation_threshold;
|
||||
int short_retry_limit; /* dot11ShortRetryLimit */
|
||||
|
@ -464,29 +472,23 @@ struct ieee80211_local {
|
|||
* deliver multicast frames both back to wireless
|
||||
* media and to the local net stack */
|
||||
|
||||
ieee80211_rx_handler *rx_pre_handlers;
|
||||
ieee80211_rx_handler *rx_handlers;
|
||||
ieee80211_tx_handler *tx_handlers;
|
||||
|
||||
struct list_head interfaces;
|
||||
|
||||
int sta_scanning;
|
||||
bool sta_sw_scanning;
|
||||
bool sta_hw_scanning;
|
||||
int scan_channel_idx;
|
||||
enum ieee80211_band scan_band;
|
||||
|
||||
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
|
||||
unsigned long last_scan_completed;
|
||||
struct delayed_work scan_work;
|
||||
struct net_device *scan_dev;
|
||||
struct ieee80211_channel *oper_channel, *scan_channel;
|
||||
struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
|
||||
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
|
||||
size_t scan_ssid_len;
|
||||
struct list_head sta_bss_list;
|
||||
struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
|
||||
spinlock_t sta_bss_lock;
|
||||
#define IEEE80211_SCAN_MATCH_SSID BIT(0)
|
||||
#define IEEE80211_SCAN_WPA_ONLY BIT(1)
|
||||
#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
|
||||
int scan_flags;
|
||||
|
||||
/* SNMP counters */
|
||||
/* dot11CountersTable */
|
||||
|
@ -503,8 +505,9 @@ struct ieee80211_local {
|
|||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
int tx_led_counter, rx_led_counter;
|
||||
struct led_trigger *tx_led, *rx_led, *assoc_led;
|
||||
char tx_led_name[32], rx_led_name[32], assoc_led_name[32];
|
||||
struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
|
||||
char tx_led_name[32], rx_led_name[32],
|
||||
assoc_led_name[32], radio_led_name[32];
|
||||
#endif
|
||||
|
||||
u32 channel_use;
|
||||
|
@ -549,14 +552,8 @@ struct ieee80211_local {
|
|||
int wifi_wme_noack_test;
|
||||
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
|
||||
|
||||
unsigned int enabled_modes; /* bitfield of allowed modes;
|
||||
* (1 << MODE_*) */
|
||||
unsigned int hw_modes; /* bitfield of supported hardware modes;
|
||||
* (1 << MODE_*) */
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct local_debugfsdentries {
|
||||
struct dentry *channel;
|
||||
struct dentry *frequency;
|
||||
struct dentry *antenna_sel_tx;
|
||||
struct dentry *antenna_sel_rx;
|
||||
|
@ -566,9 +563,7 @@ struct ieee80211_local {
|
|||
struct dentry *short_retry_limit;
|
||||
struct dentry *long_retry_limit;
|
||||
struct dentry *total_ps_buffered;
|
||||
struct dentry *mode;
|
||||
struct dentry *wep_iv;
|
||||
struct dentry *modes;
|
||||
struct dentry *statistics;
|
||||
struct local_debugfsdentries_statsdentries {
|
||||
struct dentry *transmitted_fragment_count;
|
||||
|
@ -616,6 +611,12 @@ struct ieee80211_local {
|
|||
#endif
|
||||
};
|
||||
|
||||
/* this struct represents 802.11n's RA/TID combination */
|
||||
struct ieee80211_ra_tid {
|
||||
u8 ra[ETH_ALEN];
|
||||
u16 tid;
|
||||
};
|
||||
|
||||
static inline struct ieee80211_local *hw_to_local(
|
||||
struct ieee80211_hw *hw)
|
||||
{
|
||||
|
@ -673,23 +674,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local,
|
|||
read_unlock_bh(&local->sta_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_erp_rate - Check if a rate is an ERP rate
|
||||
* @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
|
||||
* @rate: Transmission rate to check, in 100 kbps
|
||||
*
|
||||
* Check if a given rate is an Extended Rate PHY (ERP) rate.
|
||||
*/
|
||||
static inline int ieee80211_is_erp_rate(int phymode, int rate)
|
||||
{
|
||||
if (phymode == MODE_IEEE80211G) {
|
||||
if (rate != 10 && rate != 20 &&
|
||||
rate != 55 && rate != 110)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
||||
{
|
||||
return compare_ether_addr(raddr, addr) == 0 ||
|
||||
|
@ -701,13 +685,12 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
|||
int ieee80211_hw_config(struct ieee80211_local *local);
|
||||
int ieee80211_if_config(struct net_device *dev);
|
||||
int ieee80211_if_config_beacon(struct net_device *dev);
|
||||
void ieee80211_prepare_rates(struct ieee80211_local *local,
|
||||
struct ieee80211_hw_mode *mode);
|
||||
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
|
||||
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
|
||||
void ieee80211_if_setup(struct net_device *dev);
|
||||
struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
|
||||
int phymode, int hwrate);
|
||||
int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
|
||||
struct ieee80211_ht_info *req_ht_cap,
|
||||
struct ieee80211_ht_bss_info *req_bss_cap);
|
||||
|
||||
/* ieee80211_ioctl.c */
|
||||
extern const struct iw_handler_def ieee80211_iw_handler_def;
|
||||
|
@ -735,7 +718,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
|
|||
/* ieee80211_ioctl.c */
|
||||
int ieee80211_set_compression(struct ieee80211_local *local,
|
||||
struct net_device *dev, struct sta_info *sta);
|
||||
int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
|
||||
int ieee80211_set_freq(struct ieee80211_local *local, int freq);
|
||||
/* ieee80211_sta.c */
|
||||
void ieee80211_sta_timer(unsigned long data);
|
||||
void ieee80211_sta_work(struct work_struct *work);
|
||||
|
@ -749,8 +732,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
|
|||
void ieee80211_sta_req_auth(struct net_device *dev,
|
||||
struct ieee80211_if_sta *ifsta);
|
||||
int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
|
||||
void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
ieee80211_rx_result ieee80211_sta_rx_scan(
|
||||
struct net_device *dev, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
void ieee80211_rx_bss_list_init(struct net_device *dev);
|
||||
void ieee80211_rx_bss_list_deinit(struct net_device *dev);
|
||||
int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
|
||||
|
@ -759,9 +743,23 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
|
|||
u8 *addr);
|
||||
int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
|
||||
int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
|
||||
void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes);
|
||||
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u32 changed);
|
||||
void ieee80211_reset_erp_info(struct net_device *dev);
|
||||
|
||||
int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct ieee80211_ht_info *ht_info);
|
||||
int ieee80211_ht_addt_info_ie_to_ht_bss_info(
|
||||
struct ieee80211_ht_addt_info *ht_add_info_ie,
|
||||
struct ieee80211_ht_bss_info *bss_info);
|
||||
void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
|
||||
u16 tid, u8 dialog_token, u16 start_seq_num,
|
||||
u16 agg_size, u16 timeout);
|
||||
void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
|
||||
u16 initiator, u16 reason_code);
|
||||
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
|
||||
u16 tid, u16 initiator, u16 reason);
|
||||
void sta_rx_agg_session_timer_expired(unsigned long data);
|
||||
void sta_addba_resp_timer_expired(unsigned long data);
|
||||
/* ieee80211_iface.c */
|
||||
int ieee80211_if_add(struct net_device *dev, const char *name,
|
||||
struct net_device **new_dev, int type);
|
||||
|
@ -773,16 +771,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
|
|||
void ieee80211_if_free(struct net_device *dev);
|
||||
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* regdomain.c */
|
||||
void ieee80211_regdomain_init(void);
|
||||
void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
|
||||
|
||||
/* rx handling */
|
||||
extern ieee80211_rx_handler ieee80211_rx_pre_handlers[];
|
||||
extern ieee80211_rx_handler ieee80211_rx_handlers[];
|
||||
|
||||
/* tx handling */
|
||||
extern ieee80211_tx_handler ieee80211_tx_handlers[];
|
||||
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
|
||||
void ieee80211_tx_pending(unsigned long data);
|
||||
int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||
|
@ -793,8 +782,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
|||
extern void *mac80211_wiphy_privid; /* for wiphy privid */
|
||||
extern const unsigned char rfc1042_header[6];
|
||||
extern const unsigned char bridge_tunnel_header[6];
|
||||
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
|
||||
int ieee80211_is_eapol(const struct sk_buff *skb);
|
||||
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
|
||||
enum ieee80211_if_types type);
|
||||
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
|
||||
int rate, int erp, int short_preamble);
|
||||
void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "ieee80211_led.h"
|
||||
#include "ieee80211_rate.h"
|
||||
#include "wpa.h"
|
||||
#include "aes_ccm.h"
|
||||
|
@ -64,9 +65,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
|
|||
sta = sta_info_get(local, sta_addr);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
DECLARE_MAC_BUF(mac);
|
||||
printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
|
||||
MAC_FMT "\n",
|
||||
dev->name, MAC_ARG(sta_addr));
|
||||
"%s\n",
|
||||
dev->name, print_mac(mac, sta_addr));
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
return -ENOENT;
|
||||
|
@ -110,8 +112,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
|
|||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -127,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
|
|||
struct iw_request_info *info,
|
||||
char *name, char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
switch (local->hw.conf.phymode) {
|
||||
case MODE_IEEE80211A:
|
||||
strcpy(name, "IEEE 802.11a");
|
||||
break;
|
||||
case MODE_IEEE80211B:
|
||||
strcpy(name, "IEEE 802.11b");
|
||||
break;
|
||||
case MODE_IEEE80211G:
|
||||
strcpy(name, "IEEE 802.11g");
|
||||
break;
|
||||
default:
|
||||
strcpy(name, "IEEE 802.11");
|
||||
break;
|
||||
}
|
||||
strcpy(name, "IEEE 802.11");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -154,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
|
|||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct iw_range *range = (struct iw_range *) extra;
|
||||
struct ieee80211_hw_mode *mode = NULL;
|
||||
enum ieee80211_band band;
|
||||
int c = 0;
|
||||
|
||||
data->length = sizeof(struct iw_range);
|
||||
|
@ -189,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
|
|||
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
|
||||
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
|
||||
|
||||
list_for_each_entry(mode, &local->modes_list, list) {
|
||||
int i = 0;
|
||||
|
||||
if (!(local->enabled_modes & (1 << mode->mode)) ||
|
||||
(local->hw_modes & local->enabled_modes &
|
||||
(1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
|
||||
int i;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
if (!sband)
|
||||
continue;
|
||||
|
||||
while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
|
||||
struct ieee80211_channel *chan = &mode->channels[i];
|
||||
for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
|
||||
struct ieee80211_channel *chan = &sband->channels[i];
|
||||
|
||||
if (chan->flag & IEEE80211_CHAN_W_SCAN) {
|
||||
range->freq[c].i = chan->chan;
|
||||
range->freq[c].m = chan->freq * 100000;
|
||||
range->freq[c].e = 1;
|
||||
if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
|
||||
range->freq[c].i =
|
||||
ieee80211_frequency_to_channel(
|
||||
chan->center_freq);
|
||||
range->freq[c].m = chan->center_freq;
|
||||
range->freq[c].e = 6;
|
||||
c++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
range->num_channels = c;
|
||||
|
@ -217,6 +207,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
|
|||
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
|
||||
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
|
||||
|
||||
range->scan_capa |= IW_SCAN_CAPA_ESSID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,7 +220,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int type;
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_VLAN)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (*mode) {
|
||||
|
@ -245,7 +237,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == sdata->type)
|
||||
if (type == sdata->vif.type)
|
||||
return 0;
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
|
@ -264,7 +256,7 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
switch (sdata->type) {
|
||||
switch (sdata->vif.type) {
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
*mode = IW_MODE_MASTER;
|
||||
break;
|
||||
|
@ -290,28 +282,38 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
|
||||
int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
|
||||
{
|
||||
struct ieee80211_hw_mode *mode;
|
||||
int c, set = 0;
|
||||
int set = 0;
|
||||
int ret = -EINVAL;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_supported_band *sband;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(mode, &local->modes_list, list) {
|
||||
if (!(local->enabled_modes & (1 << mode->mode)))
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
if (!sband)
|
||||
continue;
|
||||
for (c = 0; c < mode->num_channels; c++) {
|
||||
struct ieee80211_channel *chan = &mode->channels[c];
|
||||
if (chan->flag & IEEE80211_CHAN_W_SCAN &&
|
||||
((chan->chan == channel) || (chan->freq == freq))) {
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
struct ieee80211_channel *chan = &sband->channels[i];
|
||||
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
if (chan->center_freq == freqMHz) {
|
||||
set = 1;
|
||||
local->oper_channel = chan;
|
||||
local->oper_hw_mode = mode;
|
||||
set++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (set)
|
||||
break;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
if (local->sta_scanning)
|
||||
if (local->sta_sw_scanning)
|
||||
ret = 0;
|
||||
else
|
||||
ret = ieee80211_hw_config(local);
|
||||
|
@ -329,24 +331,25 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
|
|||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
|
||||
sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
|
||||
/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
|
||||
if (freq->e == 0) {
|
||||
if (freq->m < 0) {
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
|
||||
sdata->u.sta.flags |=
|
||||
IEEE80211_STA_AUTO_CHANNEL_SEL;
|
||||
return 0;
|
||||
} else
|
||||
return ieee80211_set_channel(local, freq->m, -1);
|
||||
return ieee80211_set_freq(local,
|
||||
ieee80211_channel_to_frequency(freq->m));
|
||||
} else {
|
||||
int i, div = 1000000;
|
||||
for (i = 0; i < freq->e; i++)
|
||||
div /= 10;
|
||||
if (div > 0)
|
||||
return ieee80211_set_channel(local, -1, freq->m / div);
|
||||
return ieee80211_set_freq(local, freq->m / div);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -359,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
|
|||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
|
||||
/* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
|
||||
* driver for the current channel with firmware-based management */
|
||||
|
||||
freq->m = local->hw.conf.freq;
|
||||
freq->m = local->hw.conf.channel->center_freq;
|
||||
freq->e = 6;
|
||||
|
||||
return 0;
|
||||
|
@ -381,8 +381,8 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
|
|||
len--;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
int ret;
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
|
||||
if (len > IEEE80211_MAX_SSID_LEN)
|
||||
|
@ -402,7 +402,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_AP) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
|
||||
memcpy(sdata->u.ap.ssid, ssid, len);
|
||||
memset(sdata->u.ap.ssid + len, 0,
|
||||
IEEE80211_MAX_SSID_LEN - len);
|
||||
|
@ -421,8 +421,8 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
|
|||
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
int res = ieee80211_sta_get_ssid(dev, ssid, &len);
|
||||
if (res == 0) {
|
||||
data->length = len;
|
||||
|
@ -432,7 +432,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_AP) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
|
||||
len = sdata->u.ap.ssid_len;
|
||||
if (len > IW_ESSID_MAX_SIZE)
|
||||
len = IW_ESSID_MAX_SIZE;
|
||||
|
@ -452,8 +452,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
int ret;
|
||||
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
|
||||
memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
|
||||
|
@ -472,7 +472,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
|
|||
return ret;
|
||||
ieee80211_sta_req_auth(dev, &sdata->u.sta);
|
||||
return 0;
|
||||
} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
|
||||
} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
|
||||
if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
|
||||
ETH_ALEN) == 0)
|
||||
return 0;
|
||||
|
@ -490,12 +490,12 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
|
||||
ap_addr->sa_family = ARPHRD_ETHER;
|
||||
memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
|
||||
return 0;
|
||||
} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
|
||||
} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
|
||||
ap_addr->sa_family = ARPHRD_ETHER;
|
||||
memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
|
||||
return 0;
|
||||
|
@ -507,32 +507,27 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
|
|||
|
||||
static int ieee80211_ioctl_siwscan(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_point *data, char *extra)
|
||||
union iwreq_data *wrqu, char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct iw_scan_req *req = NULL;
|
||||
u8 *ssid = NULL;
|
||||
size_t ssid_len = 0;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -ENETDOWN;
|
||||
|
||||
switch (sdata->type) {
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
case IEEE80211_IF_TYPE_IBSS:
|
||||
if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
|
||||
ssid = sdata->u.sta.ssid;
|
||||
ssid_len = sdata->u.sta.ssid_len;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_IF_TYPE_AP:
|
||||
if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
|
||||
ssid = sdata->u.ap.ssid;
|
||||
ssid_len = sdata->u.ap.ssid_len;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
|
||||
sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
|
||||
sdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* if SSID was specified explicitly then use that */
|
||||
if (wrqu->data.length == sizeof(struct iw_scan_req) &&
|
||||
wrqu->data.flags & IW_SCAN_THIS_ESSID) {
|
||||
req = (struct iw_scan_req *)extra;
|
||||
ssid = req->essid;
|
||||
ssid_len = req->essid_len;
|
||||
}
|
||||
|
||||
return ieee80211_sta_req_scan(dev, ssid, ssid_len);
|
||||
|
@ -545,8 +540,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
|
|||
{
|
||||
int res;
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
if (local->sta_scanning)
|
||||
|
||||
if (local->sta_sw_scanning || local->sta_hw_scanning)
|
||||
return -EAGAIN;
|
||||
|
||||
res = ieee80211_sta_scan_results(dev, extra, data->length);
|
||||
if (res >= 0) {
|
||||
data->length = res;
|
||||
|
@ -562,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
|
|||
struct iw_param *rate, char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_hw_mode *mode;
|
||||
int i;
|
||||
int i, err = -EINVAL;
|
||||
u32 target_rate = rate->value / 100000;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (!sdata->bss)
|
||||
return -ENODEV;
|
||||
mode = local->oper_hw_mode;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
|
||||
* target_rate = X, rate->fixed = 1 means only rate X
|
||||
* target_rate = X, rate->fixed = 0 means all rates <= X */
|
||||
|
@ -578,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
|
|||
sdata->bss->force_unicast_rateidx = -1;
|
||||
if (rate->value < 0)
|
||||
return 0;
|
||||
for (i=0; i< mode->num_rates; i++) {
|
||||
struct ieee80211_rate *rates = &mode->rates[i];
|
||||
int this_rate = rates->rate;
|
||||
|
||||
for (i=0; i< sband->n_bitrates; i++) {
|
||||
struct ieee80211_rate *brate = &sband->bitrates[i];
|
||||
int this_rate = brate->bitrate;
|
||||
|
||||
if (target_rate == this_rate) {
|
||||
sdata->bss->max_ratectrl_rateidx = i;
|
||||
if (rate->fixed)
|
||||
sdata->bss->force_unicast_rateidx = i;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_giwrate(struct net_device *dev,
|
||||
|
@ -599,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
|
|||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA)
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
|
||||
sta = sta_info_get(local, sdata->u.sta.bssid);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
if (!sta)
|
||||
return -ENODEV;
|
||||
if (sta->txrate < local->oper_hw_mode->num_rates)
|
||||
rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
if (sta->txrate_idx < sband->n_bitrates)
|
||||
rate->value = sband->bitrates[sta->txrate_idx].bitrate;
|
||||
else
|
||||
rate->value = 0;
|
||||
rate->value *= 100000;
|
||||
sta_info_put(sta);
|
||||
return 0;
|
||||
}
|
||||
|
@ -621,22 +628,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
|
|||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
bool need_reconfig = 0;
|
||||
int new_power_level;
|
||||
|
||||
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
|
||||
return -EINVAL;
|
||||
if (data->txpower.flags & IW_TXPOW_RANGE)
|
||||
return -EINVAL;
|
||||
if (!data->txpower.fixed)
|
||||
return -EINVAL;
|
||||
|
||||
if (local->hw.conf.power_level != data->txpower.value) {
|
||||
local->hw.conf.power_level = data->txpower.value;
|
||||
if (data->txpower.fixed) {
|
||||
new_power_level = data->txpower.value;
|
||||
} else {
|
||||
/*
|
||||
* Automatic power level. Use maximum power for the current
|
||||
* channel. Should be part of rate control.
|
||||
*/
|
||||
struct ieee80211_channel* chan = local->hw.conf.channel;
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
new_power_level = chan->max_power;
|
||||
}
|
||||
|
||||
if (local->hw.conf.power_level != new_power_level) {
|
||||
local->hw.conf.power_level = new_power_level;
|
||||
need_reconfig = 1;
|
||||
}
|
||||
|
||||
if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
|
||||
local->hw.conf.radio_enabled = !(data->txpower.disabled);
|
||||
need_reconfig = 1;
|
||||
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
|
||||
}
|
||||
|
||||
if (need_reconfig) {
|
||||
ieee80211_hw_config(local);
|
||||
/* The return value of hw_config is not of big interest here,
|
||||
|
@ -801,8 +824,8 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev,
|
|||
struct iw_mlme *mlme = (struct iw_mlme *) extra;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->type != IEEE80211_IF_TYPE_STA &&
|
||||
sdata->type != IEEE80211_IF_TYPE_IBSS)
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
|
||||
sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mlme->cmd) {
|
||||
|
@ -904,7 +927,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
|
|||
struct iw_request_info *info,
|
||||
struct iw_param *data, char *extra)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
int ret = 0;
|
||||
|
||||
|
@ -914,32 +936,33 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
|
|||
case IW_AUTH_CIPHER_GROUP:
|
||||
case IW_AUTH_WPA_ENABLED:
|
||||
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
|
||||
break;
|
||||
case IW_AUTH_KEY_MGMT:
|
||||
if (sdata->type != IEEE80211_IF_TYPE_STA)
|
||||
break;
|
||||
case IW_AUTH_DROP_UNENCRYPTED:
|
||||
sdata->drop_unencrypted = !!data->value;
|
||||
break;
|
||||
case IW_AUTH_PRIVACY_INVOKED:
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
|
||||
/*
|
||||
* Key management was set by wpa_supplicant,
|
||||
* we only need this to associate to a network
|
||||
* that has privacy enabled regardless of not
|
||||
* having a key.
|
||||
* Privacy invoked by wpa_supplicant, store the
|
||||
* value and allow associating to a protected
|
||||
* network without having a key up front.
|
||||
*/
|
||||
sdata->u.sta.key_management_enabled = !!data->value;
|
||||
if (data->value)
|
||||
sdata->u.sta.flags |=
|
||||
IEEE80211_STA_PRIVACY_INVOKED;
|
||||
}
|
||||
break;
|
||||
case IW_AUTH_80211_AUTH_ALG:
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
|
||||
sdata->u.sta.auth_algs = data->value;
|
||||
else
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
case IW_AUTH_PRIVACY_INVOKED:
|
||||
if (local->ops->set_privacy_invoked)
|
||||
ret = local->ops->set_privacy_invoked(
|
||||
local_to_hw(local), data->value);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
|
@ -955,8 +978,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
|
||||
sta = sta_info_get(local, sdata->u.sta.bssid);
|
||||
if (!sta) {
|
||||
wstats->discard.fragment = 0;
|
||||
|
@ -984,8 +1007,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
|
|||
|
||||
switch (data->flags & IW_AUTH_INDEX) {
|
||||
case IW_AUTH_80211_AUTH_ALG:
|
||||
if (sdata->type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->type == IEEE80211_IF_TYPE_IBSS)
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
|
||||
data->value = sdata->u.sta.auth_algs;
|
||||
else
|
||||
ret = -EOPNOTSUPP;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,31 +18,26 @@
|
|||
#include "ieee80211_i.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
#define RATE_CONTROL_NUM_DOWN 20
|
||||
#define RATE_CONTROL_NUM_UP 15
|
||||
|
||||
|
||||
struct rate_control_extra {
|
||||
/* values from rate_control_get_rate() to the caller: */
|
||||
struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
|
||||
* probing */
|
||||
/* TODO: kdoc */
|
||||
struct rate_selection {
|
||||
/* Selected transmission rate */
|
||||
struct ieee80211_rate *rate;
|
||||
/* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
|
||||
struct ieee80211_rate *nonerp;
|
||||
|
||||
/* parameters from the caller to rate_control_get_rate(): */
|
||||
struct ieee80211_hw_mode *mode;
|
||||
u16 ethertype;
|
||||
/* probe with this rate, or NULL for no probing */
|
||||
struct ieee80211_rate *probe;
|
||||
};
|
||||
|
||||
|
||||
struct rate_control_ops {
|
||||
struct module *module;
|
||||
const char *name;
|
||||
void (*tx_status)(void *priv, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_tx_status *status);
|
||||
struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct rate_control_extra *extra);
|
||||
void (*get_rate)(void *priv, struct net_device *dev,
|
||||
struct ieee80211_supported_band *band,
|
||||
struct sk_buff *skb,
|
||||
struct rate_selection *sel);
|
||||
void (*rate_init)(void *priv, void *priv_sta,
|
||||
struct ieee80211_local *local, struct sta_info *sta);
|
||||
void (*clear)(void *priv);
|
||||
|
@ -72,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
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -14,6 +14,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
@ -73,36 +74,13 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
|
|||
}
|
||||
EXPORT_SYMBOL(sta_info_get);
|
||||
|
||||
int sta_info_min_txrate_get(struct ieee80211_local *local)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_hw_mode *mode;
|
||||
int min_txrate = 9999999;
|
||||
int i;
|
||||
|
||||
read_lock_bh(&local->sta_lock);
|
||||
mode = local->oper_hw_mode;
|
||||
for (i = 0; i < STA_HASH_SIZE; i++) {
|
||||
sta = local->sta_hash[i];
|
||||
while (sta) {
|
||||
if (sta->txrate < min_txrate)
|
||||
min_txrate = sta->txrate;
|
||||
sta = sta->hnext;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&local->sta_lock);
|
||||
if (min_txrate == 9999999)
|
||||
min_txrate = 0;
|
||||
|
||||
return mode->rates[min_txrate].rate;
|
||||
}
|
||||
|
||||
|
||||
static void sta_info_release(struct kref *kref)
|
||||
{
|
||||
struct sta_info *sta = container_of(kref, struct sta_info, kref);
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
/* free sta structure; it has already been removed from
|
||||
* hash table etc. external structures. Make sure that all
|
||||
|
@ -115,6 +93,10 @@ static void sta_info_release(struct kref *kref)
|
|||
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
|
||||
del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
|
||||
}
|
||||
rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
|
||||
rate_control_put(sta->rate_ctrl);
|
||||
kfree(sta);
|
||||
|
@ -132,6 +114,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
|
|||
struct net_device *dev, u8 *addr, gfp_t gfp)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
sta = kzalloc(sizeof(*sta), gfp);
|
||||
if (!sta)
|
||||
|
@ -150,6 +134,28 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
|
|||
memcpy(sta->addr, addr, ETH_ALEN);
|
||||
sta->local = local;
|
||||
sta->dev = dev;
|
||||
spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
|
||||
spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
/* timer_to_tid must be initialized with identity mapping to
|
||||
* enable session_timer's data differentiation. refer to
|
||||
* sta_rx_agg_session_timer_expired for useage */
|
||||
sta->timer_to_tid[i] = i;
|
||||
/* tid to tx queue: initialize according to HW (0 is valid) */
|
||||
sta->tid_to_tx_q[i] = local->hw.queues;
|
||||
/* rx timers */
|
||||
sta->ampdu_mlme.tid_rx[i].session_timer.function =
|
||||
sta_rx_agg_session_timer_expired;
|
||||
sta->ampdu_mlme.tid_rx[i].session_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[i];
|
||||
init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
|
||||
/* tx timers */
|
||||
sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
|
||||
sta_addba_resp_timer_expired;
|
||||
sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
|
||||
(unsigned long)&sta->timer_to_tid[i];
|
||||
init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
|
||||
}
|
||||
skb_queue_head_init(&sta->ps_tx_buf);
|
||||
skb_queue_head_init(&sta->tx_filtered);
|
||||
__sta_info_get(sta); /* sta used by caller, decremented by
|
||||
|
@ -158,14 +164,21 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
|
|||
list_add(&sta->list, &local->sta_list);
|
||||
local->num_sta++;
|
||||
sta_info_hash_add(local, sta);
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(local_to_hw(local), dev->ifindex,
|
||||
STA_NOTIFY_ADD, addr);
|
||||
if (local->ops->sta_notify) {
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
sdata = sdata->u.vlan.ap;
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_ADD, addr);
|
||||
}
|
||||
write_unlock_bh(&local->sta_lock);
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
|
||||
wiphy_name(local->hw.wiphy), MAC_ARG(addr));
|
||||
printk(KERN_DEBUG "%s: Added STA %s\n",
|
||||
wiphy_name(local->hw.wiphy), print_mac(mac, addr));
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
|
@ -204,6 +217,7 @@ void sta_info_free(struct sta_info *sta)
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
might_sleep();
|
||||
|
||||
|
@ -220,16 +234,24 @@ void sta_info_free(struct sta_info *sta)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
|
||||
wiphy_name(local->hw.wiphy), MAC_ARG(sta->addr));
|
||||
printk(KERN_DEBUG "%s: Removed STA %s\n",
|
||||
wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
|
||||
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
|
||||
|
||||
ieee80211_key_free(sta->key);
|
||||
sta->key = NULL;
|
||||
|
||||
if (local->ops->sta_notify)
|
||||
local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex,
|
||||
STA_NOTIFY_REMOVE, sta->addr);
|
||||
if (local->ops->sta_notify) {
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
|
||||
sdata = sdata->u.vlan.ap;
|
||||
|
||||
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, sta->addr);
|
||||
}
|
||||
|
||||
rate_control_remove_sta_debugfs(sta);
|
||||
ieee80211_sta_debugfs_remove(sta);
|
||||
|
@ -264,6 +286,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
|
|||
{
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
if (skb_queue_empty(&sta->ps_tx_buf))
|
||||
return;
|
||||
|
@ -282,7 +305,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
|
|||
if (skb) {
|
||||
local->total_ps_buffered--;
|
||||
printk(KERN_DEBUG "Buffered frame expired (STA "
|
||||
MAC_FMT ")\n", MAC_ARG(sta->addr));
|
||||
"%s)\n", print_mac(mac, sta->addr));
|
||||
dev_kfree_skb(skb);
|
||||
} else
|
||||
break;
|
||||
|
@ -303,7 +326,8 @@ static void sta_info_cleanup(unsigned long data)
|
|||
}
|
||||
read_unlock_bh(&local->sta_lock);
|
||||
|
||||
local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
|
||||
local->sta_cleanup.expires =
|
||||
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
|
||||
add_timer(&local->sta_cleanup);
|
||||
}
|
||||
|
||||
|
@ -342,7 +366,8 @@ void sta_info_init(struct ieee80211_local *local)
|
|||
INIT_LIST_HEAD(&local->sta_list);
|
||||
|
||||
init_timer(&local->sta_cleanup);
|
||||
local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
|
||||
local->sta_cleanup.expires =
|
||||
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
|
||||
local->sta_cleanup.data = (unsigned long) local;
|
||||
local->sta_cleanup.function = sta_info_cleanup;
|
||||
|
||||
|
|
|
@ -15,22 +15,110 @@
|
|||
#include <linux/kref.h>
|
||||
#include "ieee80211_key.h"
|
||||
|
||||
/* Stations flags (struct sta_info::flags) */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
#define WLAN_STA_PS BIT(2)
|
||||
#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
|
||||
#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
|
||||
#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
|
||||
* controlling whether STA is authorized to
|
||||
* send and receive non-IEEE 802.1X frames
|
||||
*/
|
||||
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
|
||||
/* whether this is an AP that we are associated with as a client */
|
||||
#define WLAN_STA_ASSOC_AP BIT(8)
|
||||
#define WLAN_STA_WME BIT(9)
|
||||
#define WLAN_STA_WDS BIT(27)
|
||||
/**
|
||||
* enum ieee80211_sta_info_flags - Stations flags
|
||||
*
|
||||
* These flags are used with &struct sta_info's @flags member.
|
||||
*
|
||||
* @WLAN_STA_AUTH: Station is authenticated.
|
||||
* @WLAN_STA_ASSOC: Station is associated.
|
||||
* @WLAN_STA_PS: Station is in power-save mode
|
||||
* @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered)
|
||||
* @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
|
||||
* This bit is always checked so needs to be enabled for all stations
|
||||
* when virtual port control is not in use.
|
||||
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
|
||||
* frames.
|
||||
* @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
|
||||
* @WLAN_STA_WME: Station is a QoS-STA.
|
||||
* @WLAN_STA_WDS: Station is one of our WDS peers.
|
||||
*/
|
||||
enum ieee80211_sta_info_flags {
|
||||
WLAN_STA_AUTH = 1<<0,
|
||||
WLAN_STA_ASSOC = 1<<1,
|
||||
WLAN_STA_PS = 1<<2,
|
||||
WLAN_STA_TIM = 1<<3,
|
||||
WLAN_STA_AUTHORIZED = 1<<4,
|
||||
WLAN_STA_SHORT_PREAMBLE = 1<<5,
|
||||
WLAN_STA_ASSOC_AP = 1<<6,
|
||||
WLAN_STA_WME = 1<<7,
|
||||
WLAN_STA_WDS = 1<<8,
|
||||
};
|
||||
|
||||
#define STA_TID_NUM 16
|
||||
#define ADDBA_RESP_INTERVAL HZ
|
||||
#define HT_AGG_MAX_RETRIES (0x3)
|
||||
|
||||
#define HT_AGG_STATE_INITIATOR_SHIFT (4)
|
||||
|
||||
#define HT_ADDBA_REQUESTED_MSK BIT(0)
|
||||
#define HT_ADDBA_DRV_READY_MSK BIT(1)
|
||||
#define HT_ADDBA_RECEIVED_MSK BIT(2)
|
||||
#define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3)
|
||||
#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT)
|
||||
#define HT_AGG_STATE_IDLE (0x0)
|
||||
#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
|
||||
HT_ADDBA_DRV_READY_MSK | \
|
||||
HT_ADDBA_RECEIVED_MSK)
|
||||
|
||||
/**
|
||||
* struct tid_ampdu_tx - TID aggregation information (Tx).
|
||||
*
|
||||
* @state: TID's state in session state machine.
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
* @addba_resp_timer: timer for peer's response to addba request
|
||||
* @addba_req_num: number of times addBA request has been sent.
|
||||
*/
|
||||
struct tid_ampdu_tx {
|
||||
u8 state;
|
||||
u8 dialog_token;
|
||||
u16 ssn;
|
||||
struct timer_list addba_resp_timer;
|
||||
u8 addba_req_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tid_ampdu_rx - TID aggregation information (Rx).
|
||||
*
|
||||
* @state: TID's state in session state machine.
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
* @buf_size: buffer size for incoming A-MPDUs
|
||||
* @timeout: reset timer value.
|
||||
* @head_seq_num: head sequence number in reordering buffer.
|
||||
* @stored_mpdu_num: number of MPDUs in reordering buffer
|
||||
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
|
||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||
*/
|
||||
struct tid_ampdu_rx {
|
||||
u8 state;
|
||||
u8 dialog_token;
|
||||
u16 ssn;
|
||||
u16 buf_size;
|
||||
u16 timeout;
|
||||
u16 head_seq_num;
|
||||
u16 stored_mpdu_num;
|
||||
struct sk_buff **reorder_buf;
|
||||
struct timer_list session_timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sta_ampdu_mlme - STA aggregation information.
|
||||
*
|
||||
* @tid_rx: aggregation info for Rx per TID
|
||||
* @tid_tx: aggregation info for Tx per TID
|
||||
* @ampdu_rx: for locking sections in aggregation Rx flow
|
||||
* @ampdu_tx: for locking sectionsi in aggregation Tx flow
|
||||
* @dialog_token_allocator: dialog token enumerator for each new session;
|
||||
*/
|
||||
struct sta_ampdu_mlme {
|
||||
struct tid_ampdu_rx tid_rx[STA_TID_NUM];
|
||||
struct tid_ampdu_tx tid_tx[STA_TID_NUM];
|
||||
spinlock_t ampdu_rx;
|
||||
spinlock_t ampdu_tx;
|
||||
u8 dialog_token_allocator;
|
||||
};
|
||||
|
||||
struct sta_info {
|
||||
struct kref kref;
|
||||
|
@ -59,10 +147,11 @@ struct sta_info {
|
|||
unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
|
||||
|
||||
unsigned long last_rx;
|
||||
u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
|
||||
int txrate; /* index in local->curr_rates */
|
||||
int last_txrate; /* last rate used to send a frame to this STA */
|
||||
int last_nonerp_idx;
|
||||
/* bitmap of supported rates per band */
|
||||
u64 supp_rates[IEEE80211_NUM_BANDS];
|
||||
int txrate_idx;
|
||||
/* last rates used to send a frame to this STA */
|
||||
int last_txrate_idx, last_nonerp_txrate_idx;
|
||||
|
||||
struct net_device *dev; /* which net device is this station associated
|
||||
* to */
|
||||
|
@ -99,6 +188,12 @@ struct sta_info {
|
|||
|
||||
u16 listen_interval;
|
||||
|
||||
struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities
|
||||
of this STA */
|
||||
struct sta_ampdu_mlme ampdu_mlme;
|
||||
u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */
|
||||
u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct sta_info_debugfsdentries {
|
||||
struct dentry *dir;
|
||||
|
@ -112,6 +207,7 @@ struct sta_info {
|
|||
struct dentry *wme_rx_queue;
|
||||
struct dentry *wme_tx_queue;
|
||||
#endif
|
||||
struct dentry *agg_status;
|
||||
} debugfs;
|
||||
#endif
|
||||
};
|
||||
|
@ -141,7 +237,6 @@ static inline void __sta_info_get(struct sta_info *sta)
|
|||
}
|
||||
|
||||
struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
|
||||
int sta_info_min_txrate_get(struct ieee80211_local *local);
|
||||
void sta_info_put(struct sta_info *sta);
|
||||
struct sta_info * sta_info_add(struct ieee80211_local *local,
|
||||
struct net_device *dev, u8 *addr, gfp_t gfp);
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/crypto.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/scatterlist.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
|
|||
*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
|
||||
|
||||
crypto_blkcipher_setkey(tfm, rc4key, klen);
|
||||
sg.page = virt_to_page(data);
|
||||
sg.offset = offset_in_page(data);
|
||||
sg.length = data_len + WEP_ICV_LEN;
|
||||
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
|
||||
crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
|
||||
}
|
||||
|
||||
|
@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
|
|||
__le32 crc;
|
||||
|
||||
crypto_blkcipher_setkey(tfm, rc4key, klen);
|
||||
sg.page = virt_to_page(data);
|
||||
sg.offset = offset_in_page(data);
|
||||
sg.length = data_len + WEP_ICV_LEN;
|
||||
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
|
||||
crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
|
||||
|
||||
crc = cpu_to_le32(~crc32_le(~0, data, data_len));
|
||||
|
@ -269,7 +265,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
|
|||
if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
|
||||
skb->data + hdrlen + WEP_IV_LEN,
|
||||
len)) {
|
||||
printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
@ -308,20 +305,22 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ieee80211_txrx_result
|
||||
ieee80211_rx_result
|
||||
ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
|
||||
{
|
||||
if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
|
||||
((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
|
||||
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
|
||||
return TXRX_CONTINUE;
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
|
||||
if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
|
||||
#ifdef CONFIG_MAC80211_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
|
||||
"failed\n", rx->dev->name);
|
||||
return TXRX_DROP;
|
||||
#endif /* CONFIG_MAC80211_DEBUG */
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
} else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
|
||||
ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
|
||||
|
@ -329,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
|
|||
skb_trim(rx->skb, rx->skb->len - 4);
|
||||
}
|
||||
|
||||
return TXRX_CONTINUE;
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
|
||||
|
@ -347,26 +346,16 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ieee80211_txrx_result
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
|
||||
u16 fc;
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
|
||||
((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
|
||||
(fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
|
||||
return TXRX_CONTINUE;
|
||||
|
||||
tx->u.tx.control->iv_len = WEP_IV_LEN;
|
||||
tx->u.tx.control->icv_len = WEP_ICV_LEN;
|
||||
ieee80211_tx_set_iswep(tx);
|
||||
|
||||
if (wep_encrypt_skb(tx, tx->skb) < 0) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
|
||||
return TXRX_DROP;
|
||||
return TX_DROP;
|
||||
}
|
||||
|
||||
if (tx->u.tx.extra_frag) {
|
||||
|
@ -375,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
|
|||
if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
|
||||
I802_DEBUG_INC(tx->local->
|
||||
tx_handlers_drop_wep);
|
||||
return TXRX_DROP;
|
||||
return TX_DROP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TXRX_CONTINUE;
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -3,16 +3,16 @@ config CFG80211
|
|||
|
||||
config NL80211
|
||||
bool "nl80211 new netlink interface support"
|
||||
depends CFG80211
|
||||
depends on CFG80211
|
||||
default y
|
||||
---help---
|
||||
This option turns on the new netlink interface
|
||||
(nl80211) support in cfg80211.
|
||||
This option turns on the new netlink interface
|
||||
(nl80211) support in cfg80211.
|
||||
|
||||
If =n, drivers using mac80211 will be configured via
|
||||
wireless extension support provided by that subsystem.
|
||||
If =n, drivers using mac80211 will be configured via
|
||||
wireless extension support provided by that subsystem.
|
||||
|
||||
If unsure, say Y.
|
||||
If unsure, say Y.
|
||||
|
||||
config WIRELESS_EXT
|
||||
bool "Wireless extensions"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
|
|||
return -EINVAL;
|
||||
|
||||
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
|
||||
*dev = dev_get_by_index(ifindex);
|
||||
*dev = dev_get_by_index(&init_net, ifindex);
|
||||
if (!*dev)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -61,6 +61,28 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
|||
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
|
||||
|
||||
[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
|
||||
|
||||
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
|
||||
.len = WLAN_MAX_KEY_LEN },
|
||||
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
|
||||
|
||||
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_MAX_DATA_LEN },
|
||||
[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_MAX_DATA_LEN },
|
||||
[NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
|
||||
[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
|
||||
.len = NL80211_MAX_SUPP_RATES },
|
||||
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
/* message building helper */
|
||||
|
@ -77,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
struct cfg80211_registered_device *dev)
|
||||
{
|
||||
void *hdr;
|
||||
struct nlattr *nl_bands, *nl_band;
|
||||
struct nlattr *nl_freqs, *nl_freq;
|
||||
struct nlattr *nl_rates, *nl_rate;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_rate *rate;
|
||||
int i;
|
||||
|
||||
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
|
||||
if (!hdr)
|
||||
|
@ -84,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
|
||||
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
|
||||
|
||||
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
|
||||
if (!nl_bands)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (!dev->wiphy.bands[band])
|
||||
continue;
|
||||
|
||||
nl_band = nla_nest_start(msg, band);
|
||||
if (!nl_band)
|
||||
goto nla_put_failure;
|
||||
|
||||
/* add frequencies */
|
||||
nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
|
||||
if (!nl_freqs)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
|
||||
nl_freq = nla_nest_start(msg, i);
|
||||
if (!nl_freq)
|
||||
goto nla_put_failure;
|
||||
|
||||
chan = &dev->wiphy.bands[band]->channels[i];
|
||||
NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
|
||||
chan->center_freq);
|
||||
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
|
||||
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
|
||||
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
|
||||
if (chan->flags & IEEE80211_CHAN_NO_IBSS)
|
||||
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
|
||||
if (chan->flags & IEEE80211_CHAN_RADAR)
|
||||
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
|
||||
|
||||
nla_nest_end(msg, nl_freq);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_freqs);
|
||||
|
||||
/* add bitrates */
|
||||
nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
|
||||
if (!nl_rates)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
|
||||
nl_rate = nla_nest_start(msg, i);
|
||||
if (!nl_rate)
|
||||
goto nla_put_failure;
|
||||
|
||||
rate = &dev->wiphy.bands[band]->bitrates[i];
|
||||
NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
|
||||
rate->bitrate);
|
||||
if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
||||
NLA_PUT_FLAG(msg,
|
||||
NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
|
||||
|
||||
nla_nest_end(msg, nl_rate);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_rates);
|
||||
|
||||
nla_nest_end(msg, nl_band);
|
||||
}
|
||||
nla_nest_end(msg, nl_bands);
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -241,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
|
||||
[NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
|
||||
{
|
||||
struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
|
||||
int flag;
|
||||
|
||||
*mntrflags = 0;
|
||||
|
||||
if (!nla)
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
|
||||
nla, mntr_flags_policy))
|
||||
return -EINVAL;
|
||||
|
||||
for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
|
||||
if (flags[flag])
|
||||
*mntrflags |= (1<<flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err, ifindex;
|
||||
enum nl80211_iftype type;
|
||||
struct net_device *dev;
|
||||
u32 flags;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_IFTYPE]) {
|
||||
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
|
||||
|
@ -267,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
|
||||
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
|
||||
type, err ? NULL : &flags);
|
||||
rtnl_unlock();
|
||||
|
||||
unlock:
|
||||
|
@ -280,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
||||
u32 flags;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_IFNAME])
|
||||
return -EINVAL;
|
||||
|
@ -300,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
err = drv->ops->add_virtual_intf(&drv->wiphy,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
type, err ? NULL : &flags);
|
||||
rtnl_unlock();
|
||||
|
||||
unlock:
|
||||
|
@ -335,6 +470,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
return err;
|
||||
}
|
||||
|
||||
struct get_key_cookie {
|
||||
struct sk_buff *msg;
|
||||
int error;
|
||||
};
|
||||
|
||||
static void get_key_callback(void *c, struct key_params *params)
|
||||
{
|
||||
struct get_key_cookie *cookie = c;
|
||||
|
||||
if (params->key)
|
||||
NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
|
||||
params->key_len, params->key);
|
||||
|
||||
if (params->seq)
|
||||
NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
|
||||
params->seq_len, params->seq);
|
||||
|
||||
if (params->cipher)
|
||||
NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
|
||||
params->cipher);
|
||||
|
||||
return;
|
||||
nla_put_failure:
|
||||
cookie->error = 1;
|
||||
}
|
||||
|
||||
static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
u8 key_idx = 0;
|
||||
u8 *mac_addr = NULL;
|
||||
struct get_key_cookie cookie = {
|
||||
.error = 0,
|
||||
};
|
||||
void *hdr;
|
||||
struct sk_buff *msg;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
|
||||
if (key_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->get_key) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
if (!msg) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
|
||||
NL80211_CMD_NEW_KEY);
|
||||
|
||||
if (IS_ERR(hdr)) {
|
||||
err = PTR_ERR(hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cookie.msg = msg;
|
||||
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
|
||||
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
|
||||
if (mac_addr)
|
||||
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
|
||||
&cookie, get_key_callback);
|
||||
rtnl_unlock();
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (cookie.error)
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
err = genlmsg_unicast(msg, info->snd_pid);
|
||||
goto out;
|
||||
|
||||
nla_put_failure:
|
||||
err = -ENOBUFS;
|
||||
nlmsg_free(msg);
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
u8 key_idx;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
return -EINVAL;
|
||||
|
||||
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
|
||||
if (key_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
/* currently only support setting default key */
|
||||
if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
|
||||
return -EINVAL;
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->set_default_key) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
struct key_params params;
|
||||
u8 key_idx = 0;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_KEY_DATA]) {
|
||||
params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
|
||||
params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
|
||||
params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
if (key_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Disallow pairwise keys with non-zero index unless it's WEP
|
||||
* (because current deployments use pairwise WEP keys with
|
||||
* non-zero indizes but 802.11i clearly specifies to use zero)
|
||||
*/
|
||||
if (mac_addr && key_idx &&
|
||||
params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
|
||||
params.cipher != WLAN_CIPHER_SUITE_WEP104)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: add definitions for the lengths to linux/ieee80211.h */
|
||||
switch (params.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
if (params.key_len != 5)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
if (params.key_len != 32)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
if (params.key_len != 16)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
if (params.key_len != 13)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->add_key) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
u8 key_idx = 0;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_KEY_IDX])
|
||||
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
|
||||
if (key_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->del_key) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int (*call)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct beacon_parameters *info);
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
struct beacon_parameters params;
|
||||
int haveinfo = 0;
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (info->genlhdr->cmd) {
|
||||
case NL80211_CMD_NEW_BEACON:
|
||||
/* these are required for NEW_BEACON */
|
||||
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
|
||||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
|
||||
!info->attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
call = drv->ops->add_beacon;
|
||||
break;
|
||||
case NL80211_CMD_SET_BEACON:
|
||||
call = drv->ops->set_beacon;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
|
||||
params.interval =
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
||||
haveinfo = 1;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
|
||||
params.dtim_period =
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
|
||||
haveinfo = 1;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
params.head_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
haveinfo = 1;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
|
||||
params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
params.tail_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
haveinfo = 1;
|
||||
}
|
||||
|
||||
if (!haveinfo) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = call(&drv->wiphy, dev, ¶ms);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->del_beacon) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->del_beacon(&drv->wiphy, dev);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
|
||||
[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
|
||||
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
|
||||
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static int parse_station_flags(struct nlattr *nla, u32 *staflags)
|
||||
{
|
||||
struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
|
||||
int flag;
|
||||
|
||||
*staflags = 0;
|
||||
|
||||
if (!nla)
|
||||
return 0;
|
||||
|
||||
if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
|
||||
nla, sta_flags_policy))
|
||||
return -EINVAL;
|
||||
|
||||
*staflags = STATION_FLAG_CHANGED;
|
||||
|
||||
for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
|
||||
if (flags[flag])
|
||||
*staflags |= (1<<flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
|
||||
int flags, struct net_device *dev,
|
||||
u8 *mac_addr, struct station_stats *stats)
|
||||
{
|
||||
void *hdr;
|
||||
struct nlattr *statsattr;
|
||||
|
||||
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
|
||||
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
|
||||
|
||||
statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
|
||||
if (!statsattr)
|
||||
goto nla_put_failure;
|
||||
if (stats->filled & STATION_STAT_INACTIVE_TIME)
|
||||
NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
|
||||
stats->inactive_time);
|
||||
if (stats->filled & STATION_STAT_RX_BYTES)
|
||||
NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
|
||||
stats->rx_bytes);
|
||||
if (stats->filled & STATION_STAT_TX_BYTES)
|
||||
NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
|
||||
stats->tx_bytes);
|
||||
|
||||
nla_nest_end(msg, statsattr);
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
nla_put_failure:
|
||||
return genlmsg_cancel(msg, hdr);
|
||||
}
|
||||
|
||||
|
||||
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
struct station_stats stats;
|
||||
struct sk_buff *msg;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->get_station) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
|
||||
rtnl_unlock();
|
||||
|
||||
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
goto out;
|
||||
|
||||
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
|
||||
dev, mac_addr, &stats) < 0)
|
||||
goto out_free;
|
||||
|
||||
err = genlmsg_unicast(msg, info->snd_pid);
|
||||
goto out;
|
||||
|
||||
out_free:
|
||||
nlmsg_free(msg);
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get vlan interface making sure it is on the right wiphy.
|
||||
*/
|
||||
static int get_vlan(struct nlattr *vlanattr,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device **vlan)
|
||||
{
|
||||
*vlan = NULL;
|
||||
|
||||
if (vlanattr) {
|
||||
*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
|
||||
if (!*vlan)
|
||||
return -ENODEV;
|
||||
if (!(*vlan)->ieee80211_ptr)
|
||||
return -EINVAL;
|
||||
if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
struct station_parameters params;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.listen_interval = -1;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_AID])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
|
||||
params.supported_rates =
|
||||
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
params.supported_rates_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
params.listen_interval =
|
||||
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
|
||||
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
||||
¶ms.station_flags))
|
||||
return -EINVAL;
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!drv->ops->change_station) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
if (params.vlan)
|
||||
dev_put(params.vlan);
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
struct station_parameters params;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_STA_AID])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
|
||||
return -EINVAL;
|
||||
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
params.supported_rates =
|
||||
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
params.supported_rates_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
|
||||
params.listen_interval =
|
||||
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
||||
|
||||
if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
|
||||
¶ms.station_flags))
|
||||
return -EINVAL;
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!drv->ops->add_station) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
if (params.vlan)
|
||||
dev_put(params.vlan);
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!drv->ops->del_station) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
cfg80211_put_dev(drv);
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct genl_ops nl80211_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
|
@ -374,6 +1158,73 @@ static struct genl_ops nl80211_ops[] = {
|
|||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_KEY,
|
||||
.doit = nl80211_get_key,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_KEY,
|
||||
.doit = nl80211_set_key,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_NEW_KEY,
|
||||
.doit = nl80211_new_key,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_DEL_KEY,
|
||||
.doit = nl80211_del_key,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_BEACON,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = nl80211_addset_beacon,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_NEW_BEACON,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = nl80211_addset_beacon,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_DEL_BEACON,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = nl80211_del_beacon,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_STATION,
|
||||
.doit = nl80211_get_station,
|
||||
/* TODO: implement dumpit */
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_STATION,
|
||||
.doit = nl80211_set_station,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_NEW_STATION,
|
||||
.doit = nl80211_new_station,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_DEL_STATION,
|
||||
.doit = nl80211_del_station,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
};
|
||||
|
||||
/* multicast groups */
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This regulatory domain control implementation is highly incomplete, it
|
||||
* only exists for the purpose of not regressing mac80211.
|
||||
*
|
||||
* For now, drivers can restrict the set of allowed channels by either
|
||||
* not registering those channels or setting the IEEE80211_CHAN_DISABLED
|
||||
* flag; that flag will only be *set* by this code, never *cleared.
|
||||
*
|
||||
* The usual implementation is for a driver to read a device EEPROM to
|
||||
* determine which regulatory domain it should be operating under, then
|
||||
* looking up the allowable channels in a driver-local table and finally
|
||||
* registering those channels in the wiphy structure.
|
||||
*
|
||||
* Alternatively, drivers that trust the regulatory domain control here
|
||||
* will register a complete set of capabilities and the control code
|
||||
* will restrict the set by setting the IEEE80211_CHAN_* flags.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <net/wireless.h>
|
||||
#include "core.h"
|
||||
|
||||
static char *ieee80211_regdom = "US";
|
||||
module_param(ieee80211_regdom, charp, 0444);
|
||||
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
||||
|
||||
struct ieee80211_channel_range {
|
||||
short start_freq;
|
||||
short end_freq;
|
||||
int max_power;
|
||||
int max_antenna_gain;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct ieee80211_regdomain {
|
||||
const char *code;
|
||||
const struct ieee80211_channel_range *ranges;
|
||||
int n_ranges;
|
||||
};
|
||||
|
||||
#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \
|
||||
{ _start, _end, _pwr, _ag, _flags }
|
||||
|
||||
|
||||
/*
|
||||
* Ideally, in the future, these definitions will be loaded from a
|
||||
* userspace table via some daemon.
|
||||
*/
|
||||
static const struct ieee80211_channel_range ieee80211_US_channels[] = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
RANGE_PWR(2412, 2462, 27, 6, 0),
|
||||
/* IEEE 802.11a, channels 52..64 */
|
||||
RANGE_PWR(5260, 5320, 23, 6, 0),
|
||||
/* IEEE 802.11a, channels 149..165, outdoor */
|
||||
RANGE_PWR(5745, 5825, 30, 6, 0),
|
||||
};
|
||||
|
||||
static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
|
||||
/* IEEE 802.11b/g, channels 1..14 */
|
||||
RANGE_PWR(2412, 2484, 20, 6, 0),
|
||||
/* IEEE 802.11a, channels 34..48 */
|
||||
RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
|
||||
/* IEEE 802.11a, channels 52..64 */
|
||||
RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
|
||||
IEEE80211_CHAN_RADAR),
|
||||
};
|
||||
|
||||
#define REGDOM(_code) \
|
||||
{ \
|
||||
.code = __stringify(_code), \
|
||||
.ranges = ieee80211_ ##_code## _channels, \
|
||||
.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \
|
||||
}
|
||||
|
||||
static const struct ieee80211_regdomain ieee80211_regdoms[] = {
|
||||
REGDOM(US),
|
||||
REGDOM(JP),
|
||||
};
|
||||
|
||||
|
||||
static const struct ieee80211_regdomain *get_regdom(void)
|
||||
{
|
||||
static const struct ieee80211_channel_range
|
||||
ieee80211_world_channels[] = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
RANGE_PWR(2412, 2462, 27, 6, 0),
|
||||
};
|
||||
static const struct ieee80211_regdomain regdom_world = REGDOM(world);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
|
||||
if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
|
||||
return &ieee80211_regdoms[i];
|
||||
|
||||
return ®dom_world;
|
||||
}
|
||||
|
||||
|
||||
static void handle_channel(struct ieee80211_channel *chan,
|
||||
const struct ieee80211_regdomain *rd)
|
||||
{
|
||||
int i;
|
||||
u32 flags = chan->orig_flags;
|
||||
const struct ieee80211_channel_range *rg = NULL;
|
||||
|
||||
for (i = 0; i < rd->n_ranges; i++) {
|
||||
if (rd->ranges[i].start_freq <= chan->center_freq &&
|
||||
chan->center_freq <= rd->ranges[i].end_freq) {
|
||||
rg = &rd->ranges[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rg) {
|
||||
/* not found */
|
||||
flags |= IEEE80211_CHAN_DISABLED;
|
||||
chan->flags = flags;
|
||||
return;
|
||||
}
|
||||
|
||||
chan->flags = flags;
|
||||
chan->max_antenna_gain = min(chan->orig_mag,
|
||||
rg->max_antenna_gain);
|
||||
chan->max_power = min(chan->orig_mpwr, rg->max_power);
|
||||
}
|
||||
|
||||
static void handle_band(struct ieee80211_supported_band *sband,
|
||||
const struct ieee80211_regdomain *rd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++)
|
||||
handle_channel(&sband->channels[i], rd);
|
||||
}
|
||||
|
||||
void wiphy_update_regulatory(struct wiphy *wiphy)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
const struct ieee80211_regdomain *rd = get_regdom();
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
||||
if (wiphy->bands[band])
|
||||
handle_band(wiphy->bands[band], rd);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue