mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	Upgrade b43 and mac80211.
This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211. Will do that in a seperate patch. SVN-Revision: 10466
This commit is contained in:
		
							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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										489
									
								
								package/b43/src/nphy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										489
									
								
								package/b43/src/nphy.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,489 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Broadcom B43 wireless driver
 | 
			
		||||
  IEEE 802.11n PHY support
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
 | 
			
		||||
 | 
			
		||||
  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
  it under the terms of the GNU General Public License as published by
 | 
			
		||||
  the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
  (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
  This program is distributed in the hope that it will be useful,
 | 
			
		||||
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
  GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
  You should have received a copy of the GNU General Public License
 | 
			
		||||
  along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 | 
			
		||||
  Boston, MA 02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
#include "b43.h"
 | 
			
		||||
#include "nphy.h"
 | 
			
		||||
#include "tables_nphy.h"
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
 | 
			
		||||
{//TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void b43_nphy_xmitpower(struct b43_wldev *dev)
 | 
			
		||||
{//TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_chantab_radio_upload(struct b43_wldev *dev,
 | 
			
		||||
				     const struct b43_nphy_channeltab_entry *e)
 | 
			
		||||
{
 | 
			
		||||
	b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
 | 
			
		||||
	b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
 | 
			
		||||
	b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
 | 
			
		||||
	b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
 | 
			
		||||
	b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
 | 
			
		||||
	b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_chantab_phy_upload(struct b43_wldev *dev,
 | 
			
		||||
				   const struct b43_nphy_channeltab_entry *e)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	//TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Tune the hardware to a new channel. Don't call this directly.
 | 
			
		||||
 * Use b43_radio_selectchannel() */
 | 
			
		||||
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
 | 
			
		||||
{
 | 
			
		||||
	const struct b43_nphy_channeltab_entry *tabent;
 | 
			
		||||
 | 
			
		||||
	tabent = b43_nphy_get_chantabent(dev, channel);
 | 
			
		||||
	if (!tabent)
 | 
			
		||||
		return -ESRCH;
 | 
			
		||||
 | 
			
		||||
	//FIXME enable/disable band select upper20 in RXCTL
 | 
			
		||||
	if (0 /*FIXME 5Ghz*/)
 | 
			
		||||
		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
 | 
			
		||||
	else
 | 
			
		||||
		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
 | 
			
		||||
	b43_chantab_radio_upload(dev, tabent);
 | 
			
		||||
	udelay(50);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAL10, 5);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAL10, 45);
 | 
			
		||||
	b43_radio_write16(dev, B2055_VCO_CAL10, 65);
 | 
			
		||||
	udelay(300);
 | 
			
		||||
	if (0 /*FIXME 5Ghz*/)
 | 
			
		||||
		b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
 | 
			
		||||
	else
 | 
			
		||||
		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
 | 
			
		||||
	b43_chantab_phy_upload(dev, tabent);
 | 
			
		||||
	b43_nphy_tx_power_fix(dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_radio_init2055_pre(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
 | 
			
		||||
		     ~B43_NPHY_RFCTL_CMD_PORFORCE);
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
 | 
			
		||||
		    B43_NPHY_RFCTL_CMD_CHIP0PU |
 | 
			
		||||
		    B43_NPHY_RFCTL_CMD_OEPORFORCE);
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
 | 
			
		||||
		    B43_NPHY_RFCTL_CMD_PORFORCE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_radio_init2055_post(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
 | 
			
		||||
	struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
 | 
			
		||||
	int i;
 | 
			
		||||
	u16 val;
 | 
			
		||||
 | 
			
		||||
	b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
 | 
			
		||||
		if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
 | 
			
		||||
		    (binfo->type != 0x46D) ||
 | 
			
		||||
		    (binfo->rev < 0x41)) {
 | 
			
		||||
			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
 | 
			
		||||
			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
 | 
			
		||||
			msleep(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_set(dev, B2055_CAL_MISC, 0x1);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_set(dev, B2055_CAL_MISC, 0x40);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	for (i = 0; i < 100; i++) {
 | 
			
		||||
		val = b43_radio_read16(dev, B2055_CAL_COUT2);
 | 
			
		||||
		if (val & 0x80)
 | 
			
		||||
			break;
 | 
			
		||||
		udelay(10);
 | 
			
		||||
	}
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
 | 
			
		||||
	msleep(1);
 | 
			
		||||
	b43_radio_selectchannel(dev, dev->phy.channel, 0);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
 | 
			
		||||
	b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize a Broadcom 2055 N-radio */
 | 
			
		||||
static void b43_radio_init2055(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_radio_init2055_pre(dev);
 | 
			
		||||
	if (b43_status(dev) < B43_STAT_INITIALIZED)
 | 
			
		||||
		b2055_upload_inittab(dev, 0, 1);
 | 
			
		||||
	else
 | 
			
		||||
		b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
 | 
			
		||||
	b43_radio_init2055_post(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void b43_nphy_radio_turn_on(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_radio_init2055(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void b43_nphy_radio_turn_off(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
 | 
			
		||||
		     ~B43_NPHY_RFCTL_CMD_EN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ntab_upload(dev, offset, data) do { \
 | 
			
		||||
		unsigned int i;						\
 | 
			
		||||
		for (i = 0; i < (offset##_SIZE); i++)			\
 | 
			
		||||
			b43_ntab_write(dev, (offset) + i, (data)[i]);	\
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
/* Upload the N-PHY tables. */
 | 
			
		||||
static void b43_nphy_tables_init(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* Static tables */
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
 | 
			
		||||
 | 
			
		||||
	/* Volatile tables */
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
 | 
			
		||||
	ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_nphy_workarounds(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_IQFLIP,
 | 
			
		||||
		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
 | 
			
		||||
	//FIXME the following condition is different in the specs.
 | 
			
		||||
	if (1 /* FIXME band is 2.4GHz */) {
 | 
			
		||||
		b43_phy_set(dev, B43_NPHY_CLASSCTL,
 | 
			
		||||
			    B43_NPHY_CLASSCTL_CCKEN);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_phy_mask(dev, B43_NPHY_CLASSCTL,
 | 
			
		||||
			     ~B43_NPHY_CLASSCTL_CCKEN);
 | 
			
		||||
	}
 | 
			
		||||
	b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
 | 
			
		||||
 | 
			
		||||
	/* Fixup some tables */
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
 | 
			
		||||
	b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
 | 
			
		||||
 | 
			
		||||
	//TODO set RF sequence
 | 
			
		||||
 | 
			
		||||
	/* Set narrowband clip threshold */
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
 | 
			
		||||
 | 
			
		||||
	/* Set wideband clip 2 threshold */
 | 
			
		||||
	b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
 | 
			
		||||
			~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
 | 
			
		||||
			21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
 | 
			
		||||
	b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
 | 
			
		||||
			~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
 | 
			
		||||
			21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
 | 
			
		||||
 | 
			
		||||
	/* Set Clip 2 detect */
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_C1_CGAINI,
 | 
			
		||||
		    B43_NPHY_C1_CGAINI_CL2DETECT);
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_C2_CGAINI,
 | 
			
		||||
		    B43_NPHY_C2_CGAINI_CL2DETECT);
 | 
			
		||||
 | 
			
		||||
	if (0 /*FIXME*/) {
 | 
			
		||||
		/* Set dwell lengths */
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
 | 
			
		||||
 | 
			
		||||
		/* Set gain backoff */
 | 
			
		||||
		b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
 | 
			
		||||
				~B43_NPHY_C1_CGAINI_GAINBKOFF,
 | 
			
		||||
				1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
 | 
			
		||||
		b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
 | 
			
		||||
				~B43_NPHY_C2_CGAINI_GAINBKOFF,
 | 
			
		||||
				1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
 | 
			
		||||
 | 
			
		||||
		/* Set HPVGA2 index */
 | 
			
		||||
		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
 | 
			
		||||
				~B43_NPHY_C1_INITGAIN_HPVGA2,
 | 
			
		||||
				6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
 | 
			
		||||
		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
 | 
			
		||||
				~B43_NPHY_C2_INITGAIN_HPVGA2,
 | 
			
		||||
				6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
 | 
			
		||||
 | 
			
		||||
		//FIXME verify that the specs really mean to use autoinc here.
 | 
			
		||||
		for (i = 0; i < 3; i++)
 | 
			
		||||
			b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set minimum gain value */
 | 
			
		||||
	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
 | 
			
		||||
			~B43_NPHY_C1_MINGAIN,
 | 
			
		||||
			23 << B43_NPHY_C1_MINGAIN_SHIFT);
 | 
			
		||||
	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
 | 
			
		||||
			~B43_NPHY_C2_MINGAIN,
 | 
			
		||||
			23 << B43_NPHY_C2_MINGAIN_SHIFT);
 | 
			
		||||
 | 
			
		||||
	if (phy->rev < 2) {
 | 
			
		||||
		b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
 | 
			
		||||
			     ~B43_NPHY_SCRAM_SIGCTL_SCM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set phase track alpha and beta */
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_nphy_reset_cca(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	u16 bbcfg;
 | 
			
		||||
 | 
			
		||||
	ssb_write32(dev->dev, SSB_TMSLOW,
 | 
			
		||||
		    ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
 | 
			
		||||
	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_BBCFG,
 | 
			
		||||
		      bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
 | 
			
		||||
	ssb_write32(dev->dev, SSB_TMSLOW,
 | 
			
		||||
		    ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum b43_nphy_rf_sequence {
 | 
			
		||||
	B43_RFSEQ_RX2TX,
 | 
			
		||||
	B43_RFSEQ_TX2RX,
 | 
			
		||||
	B43_RFSEQ_RESET2RX,
 | 
			
		||||
	B43_RFSEQ_UPDATE_GAINH,
 | 
			
		||||
	B43_RFSEQ_UPDATE_GAINL,
 | 
			
		||||
	B43_RFSEQ_UPDATE_GAINU,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
 | 
			
		||||
				       enum b43_nphy_rf_sequence seq)
 | 
			
		||||
{
 | 
			
		||||
	static const u16 trigger[] = {
 | 
			
		||||
		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
 | 
			
		||||
		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
 | 
			
		||||
		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
 | 
			
		||||
		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
 | 
			
		||||
		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
 | 
			
		||||
		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
 | 
			
		||||
	};
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
 | 
			
		||||
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
 | 
			
		||||
		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
 | 
			
		||||
	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
 | 
			
		||||
	for (i = 0; i < 200; i++) {
 | 
			
		||||
		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
 | 
			
		||||
			goto ok;
 | 
			
		||||
		msleep(1);
 | 
			
		||||
	}
 | 
			
		||||
	b43err(dev->wl, "RF sequence status timeout\n");
 | 
			
		||||
ok:
 | 
			
		||||
	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
 | 
			
		||||
		     ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_nphy_bphy_init(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	u16 val;
 | 
			
		||||
 | 
			
		||||
	val = 0x1E1F;
 | 
			
		||||
	for (i = 0; i < 14; i++) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
 | 
			
		||||
		val -= 0x202;
 | 
			
		||||
	}
 | 
			
		||||
	val = 0x3E3F;
 | 
			
		||||
	for (i = 0; i < 16; i++) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
 | 
			
		||||
		val -= 0x202;
 | 
			
		||||
	}
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* RSSI Calibration */
 | 
			
		||||
static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
 | 
			
		||||
{
 | 
			
		||||
	//TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int b43_phy_initn(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	u16 tmp;
 | 
			
		||||
 | 
			
		||||
	//TODO: Spectral management
 | 
			
		||||
	b43_nphy_tables_init(dev);
 | 
			
		||||
 | 
			
		||||
	/* Clear all overrides */
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
 | 
			
		||||
	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
 | 
			
		||||
		     ~(B43_NPHY_RFSEQMODE_CAOVER |
 | 
			
		||||
		       B43_NPHY_RFSEQMODE_TROVER));
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
 | 
			
		||||
 | 
			
		||||
	tmp = (phy->rev < 2) ? 64 : 59;
 | 
			
		||||
	b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
 | 
			
		||||
			~B43_NPHY_BPHY_CTL3_SCALE,
 | 
			
		||||
			tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
 | 
			
		||||
	b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
 | 
			
		||||
 | 
			
		||||
	//TODO MIMO-Config
 | 
			
		||||
	//TODO Update TX/RX chain
 | 
			
		||||
 | 
			
		||||
	if (phy->rev < 2) {
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
 | 
			
		||||
		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
 | 
			
		||||
	}
 | 
			
		||||
	b43_nphy_workarounds(dev);
 | 
			
		||||
	b43_nphy_reset_cca(dev);
 | 
			
		||||
 | 
			
		||||
	ssb_write32(dev->dev, SSB_TMSLOW,
 | 
			
		||||
		    ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
 | 
			
		||||
	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
 | 
			
		||||
	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
 | 
			
		||||
 | 
			
		||||
	b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
 | 
			
		||||
	//TODO read core1/2 clip1 thres regs
 | 
			
		||||
 | 
			
		||||
	if (1 /* FIXME Band is 2.4GHz */)
 | 
			
		||||
		b43_nphy_bphy_init(dev);
 | 
			
		||||
	//TODO disable TX power control
 | 
			
		||||
	//TODO Fix the TX power settings
 | 
			
		||||
	//TODO Init periodic calibration with reason 3
 | 
			
		||||
	b43_nphy_rssi_cal(dev, 2);
 | 
			
		||||
	b43_nphy_rssi_cal(dev, 0);
 | 
			
		||||
	b43_nphy_rssi_cal(dev, 1);
 | 
			
		||||
	//TODO get TX gain
 | 
			
		||||
	//TODO init superswitch
 | 
			
		||||
	//TODO calibrate LO
 | 
			
		||||
	//TODO idle TSSI TX pctl
 | 
			
		||||
	//TODO TX power control power setup
 | 
			
		||||
	//TODO table writes
 | 
			
		||||
	//TODO TX power control coefficients
 | 
			
		||||
	//TODO enable TX power control
 | 
			
		||||
	//TODO control antenna selection
 | 
			
		||||
	//TODO init radar detection
 | 
			
		||||
	//TODO reset channel if changed
 | 
			
		||||
 | 
			
		||||
	b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										932
									
								
								package/b43/src/nphy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										932
									
								
								package/b43/src/nphy.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,932 @@
 | 
			
		||||
#ifndef B43_NPHY_H_
 | 
			
		||||
#define B43_NPHY_H_
 | 
			
		||||
 | 
			
		||||
#include "phy.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* N-PHY registers. */
 | 
			
		||||
 | 
			
		||||
#define B43_NPHY_BBCFG				B43_PHY_N(0x001) /* BB config */
 | 
			
		||||
#define  B43_NPHY_BBCFG_RSTCCA			0x4000 /* Reset CCA */
 | 
			
		||||
#define  B43_NPHY_BBCFG_RSTRX			0x8000 /* Reset RX */
 | 
			
		||||
#define B43_NPHY_CHANNEL			B43_PHY_N(0x005) /* Channel */
 | 
			
		||||
#define B43_NPHY_TXERR				B43_PHY_N(0x007) /* TX error */
 | 
			
		||||
#define B43_NPHY_BANDCTL			B43_PHY_N(0x009) /* Band control */
 | 
			
		||||
#define  B43_NPHY_BANDCTL_5GHZ			0x0001 /* Use the 5GHz band */
 | 
			
		||||
#define B43_NPHY_4WI_ADDR			B43_PHY_N(0x00B) /* Four-wire bus address */
 | 
			
		||||
#define B43_NPHY_4WI_DATAHI			B43_PHY_N(0x00C) /* Four-wire bus data high */
 | 
			
		||||
#define B43_NPHY_4WI_DATALO			B43_PHY_N(0x00D) /* Four-wire bus data low */
 | 
			
		||||
#define B43_NPHY_BIST_STAT0			B43_PHY_N(0x00E) /* Built-in self test status 0 */
 | 
			
		||||
#define B43_NPHY_BIST_STAT1			B43_PHY_N(0x00F) /* Built-in self test status 1 */
 | 
			
		||||
 | 
			
		||||
#define B43_NPHY_C1_DESPWR			B43_PHY_N(0x018) /* Core 1 desired power */
 | 
			
		||||
#define B43_NPHY_C1_CCK_DESPWR			B43_PHY_N(0x019) /* Core 1 CCK desired power */
 | 
			
		||||
#define B43_NPHY_C1_BCLIPBKOFF			B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
 | 
			
		||||
#define B43_NPHY_C1_CCK_BCLIPBKOFF		B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
 | 
			
		||||
#define B43_NPHY_C1_CGAINI			B43_PHY_N(0x01C) /* Core 1 compute gain info */
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT	0
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT	5
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_GAINSTEP		0x1C00 /* Gain step */
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT	10
 | 
			
		||||
#define  B43_NPHY_C1_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
 | 
			
		||||
#define B43_NPHY_C1_CCK_CGAINI			B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
 | 
			
		||||
#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
 | 
			
		||||
#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
 | 
			
		||||
#define B43_NPHY_C1_MINMAX_GAIN			B43_PHY_N(0x01E) /* Core 1 min/max gain */
 | 
			
		||||
#define  B43_NPHY_C1_MINGAIN			0x00FF /* Minimum gain */
 | 
			
		||||
#define  B43_NPHY_C1_MINGAIN_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_C1_MAXGAIN			0xFF00 /* Maximum gain */
 | 
			
		||||
#define  B43_NPHY_C1_MAXGAIN_SHIFT		8
 | 
			
		||||
#define B43_NPHY_C1_CCK_MINMAX_GAIN		B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
 | 
			
		||||
#define  B43_NPHY_C1_CCK_MINGAIN		0x00FF /* Minimum gain */
 | 
			
		||||
#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_C1_CCK_MAXGAIN		0xFF00 /* Maximum gain */
 | 
			
		||||
#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT		8
 | 
			
		||||
#define B43_NPHY_C1_INITGAIN			B43_PHY_N(0x020) /* Core 1 initial gain code */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_EXTLNA		0x0001 /* External LNA index */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_LNA		0x0006 /* LNA index */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT	1
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT	3
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT	7
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_TRRX		0x1000 /* TR RX index */
 | 
			
		||||
#define  B43_NPHY_C1_INITGAIN_TRTX		0x2000 /* TR TX index */
 | 
			
		||||
#define B43_NPHY_C1_CLIP1_HIGAIN		B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
 | 
			
		||||
#define B43_NPHY_C1_CLIP1_MEDGAIN		B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
 | 
			
		||||
#define B43_NPHY_C1_CLIP1_LOGAIN		B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
 | 
			
		||||
#define B43_NPHY_C1_CLIP2_GAIN			B43_PHY_N(0x024) /* Core 1 clip2 gain code */
 | 
			
		||||
#define B43_NPHY_C1_FILTERGAIN			B43_PHY_N(0x025) /* Core 1 filter gain */
 | 
			
		||||
#define B43_NPHY_C1_LPF_QHPF_BW			B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
 | 
			
		||||
#define B43_NPHY_C1_CLIPWBTHRES			B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
 | 
			
		||||
#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
 | 
			
		||||
#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT	0
 | 
			
		||||
#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
 | 
			
		||||
#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT	6
 | 
			
		||||
#define B43_NPHY_C1_W1THRES			B43_PHY_N(0x028) /* Core 1 W1 threshold */
 | 
			
		||||
#define B43_NPHY_C1_EDTHRES			B43_PHY_N(0x029) /* Core 1 ED threshold */
 | 
			
		||||
#define B43_NPHY_C1_SMSIGTHRES			B43_PHY_N(0x02A) /* Core 1 small sig threshold */
 | 
			
		||||
#define B43_NPHY_C1_NBCLIPTHRES			B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
 | 
			
		||||
#define B43_NPHY_C1_CLIP1THRES			B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
 | 
			
		||||
#define B43_NPHY_C1_CLIP2THRES			B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
 | 
			
		||||
 | 
			
		||||
#define B43_NPHY_C2_DESPWR			B43_PHY_N(0x02E) /* Core 2 desired power */
 | 
			
		||||
#define B43_NPHY_C2_CCK_DESPWR			B43_PHY_N(0x02F) /* Core 2 CCK desired power */
 | 
			
		||||
#define B43_NPHY_C2_BCLIPBKOFF			B43_PHY_N(0x030) /* Core 2 barely clip backoff */
 | 
			
		||||
#define B43_NPHY_C2_CCK_BCLIPBKOFF		B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
 | 
			
		||||
#define B43_NPHY_C2_CGAINI			B43_PHY_N(0x032) /* Core 2 compute gain info */
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT	0
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT	5
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_GAINSTEP		0x1C00 /* Gain step */
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT	10
 | 
			
		||||
#define  B43_NPHY_C2_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
 | 
			
		||||
#define B43_NPHY_C2_CCK_CGAINI			B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
 | 
			
		||||
#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
 | 
			
		||||
#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
 | 
			
		||||
#define B43_NPHY_C2_MINMAX_GAIN			B43_PHY_N(0x034) /* Core 2 min/max gain */
 | 
			
		||||
#define  B43_NPHY_C2_MINGAIN			0x00FF /* Minimum gain */
 | 
			
		||||
#define  B43_NPHY_C2_MINGAIN_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_C2_MAXGAIN			0xFF00 /* Maximum gain */
 | 
			
		||||
#define  B43_NPHY_C2_MAXGAIN_SHIFT		8
 | 
			
		||||
#define B43_NPHY_C2_CCK_MINMAX_GAIN		B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
 | 
			
		||||
#define  B43_NPHY_C2_CCK_MINGAIN		0x00FF /* Minimum gain */
 | 
			
		||||
#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_C2_CCK_MAXGAIN		0xFF00 /* Maximum gain */
 | 
			
		||||
#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT		8
 | 
			
		||||
#define B43_NPHY_C2_INITGAIN			B43_PHY_N(0x036) /* Core 2 initial gain code */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_EXTLNA		0x0001 /* External LNA index */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_LNA		0x0006 /* LNA index */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT	1
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT	3
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT	7
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_TRRX		0x1000 /* TR RX index */
 | 
			
		||||
#define  B43_NPHY_C2_INITGAIN_TRTX		0x2000 /* TR TX index */
 | 
			
		||||
#define B43_NPHY_C2_CLIP1_HIGAIN		B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
 | 
			
		||||
#define B43_NPHY_C2_CLIP1_MEDGAIN		B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
 | 
			
		||||
#define B43_NPHY_C2_CLIP1_LOGAIN		B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
 | 
			
		||||
#define B43_NPHY_C2_CLIP2_GAIN			B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
 | 
			
		||||
#define B43_NPHY_C2_FILTERGAIN			B43_PHY_N(0x03B) /* Core 2 filter gain */
 | 
			
		||||
#define B43_NPHY_C2_LPF_QHPF_BW			B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
 | 
			
		||||
#define B43_NPHY_C2_CLIPWBTHRES			B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
 | 
			
		||||
#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
 | 
			
		||||
#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT	0
 | 
			
		||||
#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
 | 
			
		||||
#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT	6
 | 
			
		||||
#define B43_NPHY_C2_W1THRES			B43_PHY_N(0x03E) /* Core 2 W1 threshold */
 | 
			
		||||
#define B43_NPHY_C2_EDTHRES			B43_PHY_N(0x03F) /* Core 2 ED threshold */
 | 
			
		||||
#define B43_NPHY_C2_SMSIGTHRES			B43_PHY_N(0x040) /* Core 2 small sig threshold */
 | 
			
		||||
#define B43_NPHY_C2_NBCLIPTHRES			B43_PHY_N(0x041) /* Core 2 NB clip threshold */
 | 
			
		||||
#define B43_NPHY_C2_CLIP1THRES			B43_PHY_N(0x042) /* Core 2 clip1 threshold */
 | 
			
		||||
#define B43_NPHY_C2_CLIP2THRES			B43_PHY_N(0x043) /* Core 2 clip2 threshold */
 | 
			
		||||
 | 
			
		||||
#define B43_NPHY_CRS_THRES1			B43_PHY_N(0x044) /* CRS threshold 1 */
 | 
			
		||||
#define B43_NPHY_CRS_THRES2			B43_PHY_N(0x045) /* CRS threshold 2 */
 | 
			
		||||
#define B43_NPHY_CRS_THRES3			B43_PHY_N(0x046) /* CRS threshold 3 */
 | 
			
		||||
#define B43_NPHY_CRSCTL				B43_PHY_N(0x047) /* CRS control */
 | 
			
		||||
#define B43_NPHY_DCFADDR			B43_PHY_N(0x048) /* DC filter address */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM0			B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM1			B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM2			B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
 | 
			
		||||
#define B43_NPHY_RXF20_DENOM0			B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
 | 
			
		||||
#define B43_NPHY_RXF20_DENOM1			B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM10			B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM11			B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
 | 
			
		||||
#define B43_NPHY_RXF20_NUM12			B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
 | 
			
		||||
#define B43_NPHY_RXF20_DENOM10			B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
 | 
			
		||||
#define B43_NPHY_RXF20_DENOM11			B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM0			B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM1			B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM2			B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
 | 
			
		||||
#define B43_NPHY_RXF40_DENOM0			B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
 | 
			
		||||
#define B43_NPHY_RXF40_DENOM1			B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM10			B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM11			B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
 | 
			
		||||
#define B43_NPHY_RXF40_NUM12			B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
 | 
			
		||||
#define B43_NPHY_RXF40_DENOM10			B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
 | 
			
		||||
#define B43_NPHY_RXF40_DENOM11			B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
 | 
			
		||||
#define B43_NPHY_PPROC_RSTLEN			B43_PHY_N(0x060) /* Packet processing reset length */
 | 
			
		||||
#define B43_NPHY_INITCARR_DLEN			B43_PHY_N(0x061) /* Initial carrier detection length */
 | 
			
		||||
#define B43_NPHY_CLIP1CARR_DLEN			B43_PHY_N(0x062) /* Clip1 carrier detection length */
 | 
			
		||||
#define B43_NPHY_CLIP2CARR_DLEN			B43_PHY_N(0x063) /* Clip2 carrier detection length */
 | 
			
		||||
#define B43_NPHY_INITGAIN_SLEN			B43_PHY_N(0x064) /* Initial gain settle length */
 | 
			
		||||
#define B43_NPHY_CLIP1GAIN_SLEN			B43_PHY_N(0x065) /* Clip1 gain settle length */
 | 
			
		||||
#define B43_NPHY_CLIP2GAIN_SLEN			B43_PHY_N(0x066) /* Clip2 gain settle length */
 | 
			
		||||
#define B43_NPHY_PACKGAIN_SLEN			B43_PHY_N(0x067) /* Packet gain settle length */
 | 
			
		||||
#define B43_NPHY_CARRSRC_TLEN			B43_PHY_N(0x068) /* Carrier search timeout length */
 | 
			
		||||
#define B43_NPHY_TISRC_TLEN			B43_PHY_N(0x069) /* Timing search timeout length */
 | 
			
		||||
#define B43_NPHY_ENDROP_TLEN			B43_PHY_N(0x06A) /* Energy drop timeout length */
 | 
			
		||||
#define B43_NPHY_CLIP1_NBDWELL_LEN		B43_PHY_N(0x06B) /* Clip1 NB dwell length */
 | 
			
		||||
#define B43_NPHY_CLIP2_NBDWELL_LEN		B43_PHY_N(0x06C) /* Clip2 NB dwell length */
 | 
			
		||||
#define B43_NPHY_W1CLIP1_DWELL_LEN		B43_PHY_N(0x06D) /* W1 clip1 dwell length */
 | 
			
		||||
#define B43_NPHY_W1CLIP2_DWELL_LEN		B43_PHY_N(0x06E) /* W1 clip2 dwell length */
 | 
			
		||||
#define B43_NPHY_W2CLIP1_DWELL_LEN		B43_PHY_N(0x06F) /* W2 clip1 dwell length */
 | 
			
		||||
#define B43_NPHY_PLOAD_CSENSE_EXTLEN		B43_PHY_N(0x070) /* Payload carrier sense extension length */
 | 
			
		||||
#define B43_NPHY_EDROP_CSENSE_EXTLEN		B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
 | 
			
		||||
#define B43_NPHY_TABLE_ADDR			B43_PHY_N(0x072) /* Table address */
 | 
			
		||||
#define B43_NPHY_TABLE_DATALO			B43_PHY_N(0x073) /* Table data low */
 | 
			
		||||
#define B43_NPHY_TABLE_DATAHI			B43_PHY_N(0x074) /* Table data high */
 | 
			
		||||
#define B43_NPHY_WWISE_LENIDX			B43_PHY_N(0x075) /* WWiSE length index */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_LENIDX			B43_PHY_N(0x076) /* TGNsync length index */
 | 
			
		||||
#define B43_NPHY_TXMACIF_HOLDOFF		B43_PHY_N(0x077) /* TX MAC IF Hold off */
 | 
			
		||||
#define B43_NPHY_RFCTL_CMD			B43_PHY_N(0x078) /* RF control (command) */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_START		0x0001 /* Start sequence */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_RXTX		0x0002 /* RX/TX */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_CORESEL		0x0038 /* Core select */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT	3
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_PORFORCE		0x0040 /* POR force */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_OEPORFORCE		0x0080 /* OE POR force */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_RXEN		0x0100 /* RX enable */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_TXEN		0x0200 /* TX enable */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_CHIP0PU		0x0400 /* Chip0 PU */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_EN			0x0800 /* Radio enabled */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_SEQENCORE		0xF000 /* Seq en core */
 | 
			
		||||
#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT	12
 | 
			
		||||
#define B43_NPHY_RFCTL_RSSIO1			B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_RXPD		0x0001 /* RX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_TXPD		0x0002 /* TX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_PAPD		0x0004 /* PA PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL		0x0030 /* RSSI control */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_LPFBW		0x00C0 /* LPF bandwidth */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI		0x0100 /* HPF bandwidth high */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO		0x0200 /* HIQ dis core */
 | 
			
		||||
#define B43_NPHY_RFCTL_RXG1			B43_PHY_N(0x07B) /* RF control (RX gain 1) */
 | 
			
		||||
#define B43_NPHY_RFCTL_TXG1			B43_PHY_N(0x07C) /* RF control (TX gain 1) */
 | 
			
		||||
#define B43_NPHY_RFCTL_RSSIO2			B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_RXPD		0x0001 /* RX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_TXPD		0x0002 /* TX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_PAPD		0x0004 /* PA PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL		0x0030 /* RSSI control */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_LPFBW		0x00C0 /* LPF bandwidth */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI		0x0100 /* HPF bandwidth high */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO		0x0200 /* HIQ dis core */
 | 
			
		||||
#define B43_NPHY_RFCTL_RXG2			B43_PHY_N(0x07E) /* RF control (RX gain 2) */
 | 
			
		||||
#define B43_NPHY_RFCTL_TXG2			B43_PHY_N(0x07F) /* RF control (TX gain 2) */
 | 
			
		||||
#define B43_NPHY_RFCTL_RSSIO3			B43_PHY_N(0x080) /* RF control (RSSI others 3) */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_RXPD		0x0001 /* RX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_TXPD		0x0002 /* TX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_PAPD		0x0004 /* PA PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL		0x0030 /* RSSI control */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_LPFBW		0x00C0 /* LPF bandwidth */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI		0x0100 /* HPF bandwidth high */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO		0x0200 /* HIQ dis core */
 | 
			
		||||
#define B43_NPHY_RFCTL_RXG3			B43_PHY_N(0x081) /* RF control (RX gain 3) */
 | 
			
		||||
#define B43_NPHY_RFCTL_TXG3			B43_PHY_N(0x082) /* RF control (TX gain 3) */
 | 
			
		||||
#define B43_NPHY_RFCTL_RSSIO4			B43_PHY_N(0x083) /* RF control (RSSI others 4) */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_RXPD		0x0001 /* RX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_TXPD		0x0002 /* TX PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_PAPD		0x0004 /* PA PD */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL		0x0030 /* RSSI control */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_LPFBW		0x00C0 /* LPF bandwidth */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI		0x0100 /* HPF bandwidth high */
 | 
			
		||||
#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO		0x0200 /* HIQ dis core */
 | 
			
		||||
#define B43_NPHY_RFCTL_RXG4			B43_PHY_N(0x084) /* RF control (RX gain 4) */
 | 
			
		||||
#define B43_NPHY_RFCTL_TXG4			B43_PHY_N(0x085) /* RF control (TX gain 4) */
 | 
			
		||||
#define B43_NPHY_C1_TXIQ_COMP_OFF		B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
 | 
			
		||||
#define B43_NPHY_C2_TXIQ_COMP_OFF		B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
 | 
			
		||||
#define B43_NPHY_C1_TXCTL			B43_PHY_N(0x08B) /* Core 1 TX control */
 | 
			
		||||
#define B43_NPHY_C2_TXCTL			B43_PHY_N(0x08C) /* Core 2 TX control */
 | 
			
		||||
#define B43_NPHY_SCRAM_SIGCTL			B43_PHY_N(0x090) /* Scram signal control */
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_INITST		0x007F /* Initial state value */
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT	0
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_SCM		0x0080 /* Scram control mode */
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_SICE		0x0100 /* Scram index control enable */
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_START		0xFE00 /* Scram start bit */
 | 
			
		||||
#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT	9
 | 
			
		||||
#define B43_NPHY_RFCTL_INTC1			B43_PHY_N(0x091) /* RF control (intc 1) */
 | 
			
		||||
#define B43_NPHY_RFCTL_INTC2			B43_PHY_N(0x092) /* RF control (intc 2) */
 | 
			
		||||
#define B43_NPHY_RFCTL_INTC3			B43_PHY_N(0x093) /* RF control (intc 3) */
 | 
			
		||||
#define B43_NPHY_RFCTL_INTC4			B43_PHY_N(0x094) /* RF control (intc 4) */
 | 
			
		||||
#define B43_NPHY_NRDTO_WWISE			B43_PHY_N(0x095) /* # datatones WWiSE */
 | 
			
		||||
#define B43_NPHY_NRDTO_TGNSYNC			B43_PHY_N(0x096) /* # datatones TGNsync */
 | 
			
		||||
#define B43_NPHY_SIGFMOD_WWISE			B43_PHY_N(0x097) /* Signal field mod WWiSE */
 | 
			
		||||
#define B43_NPHY_LEG_SIGFMOD_11N		B43_PHY_N(0x098) /* Legacy signal field mod 11n */
 | 
			
		||||
#define B43_NPHY_HT_SIGFMOD_11N			B43_PHY_N(0x099) /* HT signal field mod 11n */
 | 
			
		||||
#define B43_NPHY_C1_RXIQ_COMPA0			B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
 | 
			
		||||
#define B43_NPHY_C1_RXIQ_COMPB0			B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
 | 
			
		||||
#define B43_NPHY_C2_RXIQ_COMPA1			B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
 | 
			
		||||
#define B43_NPHY_C2_RXIQ_COMPB1			B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
 | 
			
		||||
#define B43_NPHY_RXCTL				B43_PHY_N(0x0A0) /* RX control */
 | 
			
		||||
#define  B43_NPHY_RXCTL_BSELU20			0x0010 /* Band select upper 20 */
 | 
			
		||||
#define  B43_NPHY_RXCTL_RIFSEN			0x0080 /* RIFS enable */
 | 
			
		||||
#define B43_NPHY_RFSEQMODE			B43_PHY_N(0x0A1) /* RF seq mode */
 | 
			
		||||
#define  B43_NPHY_RFSEQMODE_CAOVER		0x0001 /* Core active override */
 | 
			
		||||
#define  B43_NPHY_RFSEQMODE_TROVER		0x0002 /* Trigger override */
 | 
			
		||||
#define B43_NPHY_RFSEQCA			B43_PHY_N(0x0A2) /* RF seq core active */
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_TXEN			0x000F /* TX enable */
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_TXEN_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_RXEN			0x00F0 /* RX enable */
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_RXEN_SHIFT		4
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_TXDIS			0x0F00 /* TX disable */
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT		8
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_RXDIS			0xF000 /* RX disable */
 | 
			
		||||
#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT		12
 | 
			
		||||
#define B43_NPHY_RFSEQTR			B43_PHY_N(0x0A3) /* RF seq trigger */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_RX2TX			0x0001 /* RX2TX */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_TX2RX			0x0002 /* TX2RX */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_UPGH			0x0004 /* Update gain H */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_UPGL			0x0008 /* Update gain L */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_UPGU			0x0010 /* Update gain U */
 | 
			
		||||
#define  B43_NPHY_RFSEQTR_RST2RX		0x0020 /* Reset to RX */
 | 
			
		||||
#define B43_NPHY_RFSEQST			B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
 | 
			
		||||
#define B43_NPHY_AFECTL_OVER			B43_PHY_N(0x0A5) /* AFE control override */
 | 
			
		||||
#define B43_NPHY_AFECTL_C1			B43_PHY_N(0x0A6) /* AFE control core 1 */
 | 
			
		||||
#define B43_NPHY_AFECTL_C2			B43_PHY_N(0x0A7) /* AFE control core 2 */
 | 
			
		||||
#define B43_NPHY_AFECTL_C3			B43_PHY_N(0x0A8) /* AFE control core 3 */
 | 
			
		||||
#define B43_NPHY_AFECTL_C4			B43_PHY_N(0x0A9) /* AFE control core 4 */
 | 
			
		||||
#define B43_NPHY_AFECTL_DACGAIN1		B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
 | 
			
		||||
#define B43_NPHY_AFECTL_DACGAIN2		B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
 | 
			
		||||
#define B43_NPHY_AFECTL_DACGAIN3		B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
 | 
			
		||||
#define B43_NPHY_AFECTL_DACGAIN4		B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
 | 
			
		||||
#define B43_NPHY_STR_ADDR1			B43_PHY_N(0x0AE) /* STR address 1 */
 | 
			
		||||
#define B43_NPHY_STR_ADDR2			B43_PHY_N(0x0AF) /* STR address 2 */
 | 
			
		||||
#define B43_NPHY_CLASSCTL			B43_PHY_N(0x0B0) /* Classifier control */
 | 
			
		||||
#define  B43_NPHY_CLASSCTL_CCKEN		0x0001 /* CCK enable */
 | 
			
		||||
#define  B43_NPHY_CLASSCTL_OFDMEN		0x0002 /* OFDM enable */
 | 
			
		||||
#define  B43_NPHY_CLASSCTL_WAITEDEN		0x0004 /* Waited enable */
 | 
			
		||||
#define B43_NPHY_IQFLIP				B43_PHY_N(0x0B1) /* I/Q flip */
 | 
			
		||||
#define  B43_NPHY_IQFLIP_ADC1			0x0001 /* ADC1 */
 | 
			
		||||
#define  B43_NPHY_IQFLIP_ADC2			0x0010 /* ADC2 */
 | 
			
		||||
#define B43_NPHY_SISO_SNR_THRES			B43_PHY_N(0x0B2) /* SISO SNR threshold */
 | 
			
		||||
#define B43_NPHY_SIGMA_N_MULT			B43_PHY_N(0x0B3) /* Sigma N multiplier */
 | 
			
		||||
#define B43_NPHY_TXMACDELAY			B43_PHY_N(0x0B4) /* TX MAC delay */
 | 
			
		||||
#define B43_NPHY_TXFRAMEDELAY			B43_PHY_N(0x0B5) /* TX frame delay */
 | 
			
		||||
#define B43_NPHY_MLPARM				B43_PHY_N(0x0B6) /* ML parameters */
 | 
			
		||||
#define B43_NPHY_MLCTL				B43_PHY_N(0x0B7) /* ML control */
 | 
			
		||||
#define B43_NPHY_WWISE_20NCYCDAT		B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
 | 
			
		||||
#define B43_NPHY_WWISE_40NCYCDAT		B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_20NCYCDAT		B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_40NCYCDAT		B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
 | 
			
		||||
#define B43_NPHY_INITSWIZP			B43_PHY_N(0x0BC) /* Initial swizzle pattern */
 | 
			
		||||
#define B43_NPHY_TXTAILCNT			B43_PHY_N(0x0BD) /* TX tail count value */
 | 
			
		||||
#define B43_NPHY_BPHY_CTL1			B43_PHY_N(0x0BE) /* B PHY control 1 */
 | 
			
		||||
#define B43_NPHY_BPHY_CTL2			B43_PHY_N(0x0BF) /* B PHY control 2 */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL2_LUT			0x001F /* LUT index */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL2_MACDEL		0x7FE0 /* MAC delay */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT	5
 | 
			
		||||
#define B43_NPHY_IQLOCAL_CMD			B43_PHY_N(0x0C0) /* I/Q LO cal command */
 | 
			
		||||
#define  B43_NPHY_IQLOCAL_CMD_EN		0x8000
 | 
			
		||||
#define B43_NPHY_IQLOCAL_CMDNNUM		B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
 | 
			
		||||
#define B43_NPHY_IQLOCAL_CMDGCTL		B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
 | 
			
		||||
#define B43_NPHY_SAMP_CMD			B43_PHY_N(0x0C3) /* Sample command */
 | 
			
		||||
#define  B43_NPHY_SAMP_CMD_STOP			0x0002 /* Stop */
 | 
			
		||||
#define B43_NPHY_SAMP_LOOPCNT			B43_PHY_N(0x0C4) /* Sample loop count */
 | 
			
		||||
#define B43_NPHY_SAMP_WAITCNT			B43_PHY_N(0x0C5) /* Sample wait count */
 | 
			
		||||
#define B43_NPHY_SAMP_DEPCNT			B43_PHY_N(0x0C6) /* Sample depth count */
 | 
			
		||||
#define B43_NPHY_SAMP_STAT			B43_PHY_N(0x0C7) /* Sample status */
 | 
			
		||||
#define B43_NPHY_GPIO_LOOEN			B43_PHY_N(0x0C8) /* GPIO low out enable */
 | 
			
		||||
#define B43_NPHY_GPIO_HIOEN			B43_PHY_N(0x0C9) /* GPIO high out enable */
 | 
			
		||||
#define B43_NPHY_GPIO_SEL			B43_PHY_N(0x0CA) /* GPIO select */
 | 
			
		||||
#define B43_NPHY_GPIO_CLKCTL			B43_PHY_N(0x0CB) /* GPIO clock control */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_AS0			B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_AS1			B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_AS2			B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B32S0			B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B1S0			B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B32S1			B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B1S1			B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B32S2			B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_B1S2			B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
 | 
			
		||||
#define B43_NPHY_SIGFLDTOL			B43_PHY_N(0x0D5) /* Signal fld tolerance */
 | 
			
		||||
#define B43_NPHY_TXSERFLD			B43_PHY_N(0x0D6) /* TX service field */
 | 
			
		||||
#define B43_NPHY_AFESEQ_RX2TX_PUD		B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
 | 
			
		||||
#define B43_NPHY_AFESEQ_TX2RX_PUD		B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_SCRAMI0		B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_SCRAMI1		B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
 | 
			
		||||
#define B43_NPHY_INITSWIZPATTLEG		B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
 | 
			
		||||
#define B43_NPHY_BPHY_CTL3			B43_PHY_N(0x0DC) /* B PHY control 3 */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL3_SCALE		0x00FF /* Scale */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL3_FSC			0xFF00 /* Frame start count value */
 | 
			
		||||
#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT		8
 | 
			
		||||
#define B43_NPHY_BPHY_CTL4			B43_PHY_N(0x0DD) /* B PHY control 4 */
 | 
			
		||||
#define B43_NPHY_C1_TXBBMULT			B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
 | 
			
		||||
#define B43_NPHY_C2_TXBBMULT			B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_AS0			B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_AS1			B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_AS2			B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B32S0			B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B1S0			B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B32S1			B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B1S1			B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B32S2			B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_B1S2			B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
 | 
			
		||||
#define B43_NPHY_BIST_STAT2			B43_PHY_N(0x0EA) /* BIST status 2 */
 | 
			
		||||
#define B43_NPHY_BIST_STAT3			B43_PHY_N(0x0EB) /* BIST status 3 */
 | 
			
		||||
#define B43_NPHY_RFCTL_OVER			B43_PHY_N(0x0EC) /* RF control override */
 | 
			
		||||
#define B43_NPHY_MIMOCFG			B43_PHY_N(0x0ED) /* MIMO config */
 | 
			
		||||
#define  B43_NPHY_MIMOCFG_GFMIX			0x0004 /* Greenfield or mixed mode */
 | 
			
		||||
#define  B43_NPHY_MIMOCFG_AUTO			0x0100 /* Greenfield/mixed mode auto */
 | 
			
		||||
#define B43_NPHY_RADAR_BLNKCTL			B43_PHY_N(0x0EE) /* Radar blank control */
 | 
			
		||||
#define B43_NPHY_A0RADAR_FIFOCTL		B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
 | 
			
		||||
#define B43_NPHY_A1RADAR_FIFOCTL		B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
 | 
			
		||||
#define B43_NPHY_A0RADAR_FIFODAT		B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
 | 
			
		||||
#define B43_NPHY_A1RADAR_FIFODAT		B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
 | 
			
		||||
#define B43_NPHY_RADAR_THRES0			B43_PHY_N(0x0F3) /* Radar threshold 0 */
 | 
			
		||||
#define B43_NPHY_RADAR_THRES1			B43_PHY_N(0x0F4) /* Radar threshold 1 */
 | 
			
		||||
#define B43_NPHY_RADAR_THRES0R			B43_PHY_N(0x0F5) /* Radar threshold 0R */
 | 
			
		||||
#define B43_NPHY_RADAR_THRES1R			B43_PHY_N(0x0F6) /* Radar threshold 1R */
 | 
			
		||||
#define B43_NPHY_CSEN_20IN40_DLEN		B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_LO1		B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_UP1		B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_LO2		B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_UP2		B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_LO3		B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_UP3		B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_LO4		B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_TRSW_UP4		B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_LNAPA1		B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_LNAPA2		B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_LNAPA3		B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
 | 
			
		||||
#define B43_NPHY_RFCTL_LUT_LNAPA4		B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_CRCM0			B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_CRCM1			B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_CRCM2			B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_CRCM3			B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
 | 
			
		||||
#define B43_NPHY_TGNSYNC_CRCM4			B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
 | 
			
		||||
#define B43_NPHY_CRCPOLY			B43_PHY_N(0x109) /* CRC polynomial */
 | 
			
		||||
#define B43_NPHY_SIGCNT				B43_PHY_N(0x10A) /* # sig count */
 | 
			
		||||
#define B43_NPHY_SIGSTARTBIT_CTL		B43_PHY_N(0x10B) /* Sig start bit control */
 | 
			
		||||
#define B43_NPHY_CRCPOLY_ORDER			B43_PHY_N(0x10C) /* CRC polynomial order */
 | 
			
		||||
#define B43_NPHY_RFCTL_CST0			B43_PHY_N(0x10D) /* RF control core swap table 0 */
 | 
			
		||||
#define B43_NPHY_RFCTL_CST1			B43_PHY_N(0x10E) /* RF control core swap table 1 */
 | 
			
		||||
#define B43_NPHY_RFCTL_CST2O			B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
 | 
			
		||||
#define B43_NPHY_BPHY_CTL5			B43_PHY_N(0x111) /* B PHY control 5 */
 | 
			
		||||
#define B43_NPHY_RFSEQ_LPFBW			B43_PHY_N(0x112) /* RF seq LPF bandwidth */
 | 
			
		||||
#define B43_NPHY_TSSIBIAS1			B43_PHY_N(0x114) /* TSSI bias val 1 */
 | 
			
		||||
#define B43_NPHY_TSSIBIAS2			B43_PHY_N(0x115) /* TSSI bias val 2 */
 | 
			
		||||
#define  B43_NPHY_TSSIBIAS_BIAS			0x00FF /* Bias */
 | 
			
		||||
#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TSSIBIAS_VAL			0xFF00 /* Value */
 | 
			
		||||
#define  B43_NPHY_TSSIBIAS_VAL_SHIFT		8
 | 
			
		||||
#define B43_NPHY_ESTPWR1			B43_PHY_N(0x118) /* Estimated power 1 */
 | 
			
		||||
#define B43_NPHY_ESTPWR2			B43_PHY_N(0x119) /* Estimated power 2 */
 | 
			
		||||
#define  B43_NPHY_ESTPWR_PWR			0x00FF /* Estimated power */
 | 
			
		||||
#define  B43_NPHY_ESTPWR_PWR_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_ESTPWR_VALID			0x0100 /* Estimated power valid */
 | 
			
		||||
#define B43_NPHY_TSSI_MAXTXFDT			B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
 | 
			
		||||
#define  B43_NPHY_TSSI_MAXTXFDT_VAL		0x00FF /* max TX frame delay time */
 | 
			
		||||
#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT	0
 | 
			
		||||
#define B43_NPHY_TSSI_MAXTDT			B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
 | 
			
		||||
#define  B43_NPHY_TSSI_MAXTDT_VAL		0x00FF /* max TSSI delay time */
 | 
			
		||||
#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT		0
 | 
			
		||||
#define B43_NPHY_ITSSI1				B43_PHY_N(0x11E) /* TSSI idle 1 */
 | 
			
		||||
#define B43_NPHY_ITSSI2				B43_PHY_N(0x11F) /* TSSI idle 2 */
 | 
			
		||||
#define  B43_NPHY_ITSSI_VAL			0x00FF /* Idle TSSI */
 | 
			
		||||
#define  B43_NPHY_ITSSI_VAL_SHIFT		0
 | 
			
		||||
#define B43_NPHY_TSSIMODE			B43_PHY_N(0x122) /* TSSI mode */
 | 
			
		||||
#define  B43_NPHY_TSSIMODE_EN			0x0001 /* TSSI enable */
 | 
			
		||||
#define  B43_NPHY_TSSIMODE_PDEN			0x0002 /* Power det enable */
 | 
			
		||||
#define B43_NPHY_RXMACIFM			B43_PHY_N(0x123) /* RX Macif mode */
 | 
			
		||||
#define B43_NPHY_CRSIT_COCNT_LO			B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
 | 
			
		||||
#define B43_NPHY_CRSIT_COCNT_HI			B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
 | 
			
		||||
#define B43_NPHY_CRSIT_MTCNT_LO			B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
 | 
			
		||||
#define B43_NPHY_CRSIT_MTCNT_HI			B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
 | 
			
		||||
#define B43_NPHY_SAMTWC				B43_PHY_N(0x128) /* Sample tail wait count */
 | 
			
		||||
#define B43_NPHY_IQEST_CMD			B43_PHY_N(0x129) /* I/Q estimate command */
 | 
			
		||||
#define  B43_NPHY_IQEST_CMD_START		0x0001 /* Start */
 | 
			
		||||
#define  B43_NPHY_IQEST_CMD_MODE		0x0002 /* Mode */
 | 
			
		||||
#define B43_NPHY_IQEST_WT			B43_PHY_N(0x12A) /* I/Q estimate wait time */
 | 
			
		||||
#define  B43_NPHY_IQEST_WT_VAL			0x00FF /* Wait time */
 | 
			
		||||
#define  B43_NPHY_IQEST_WT_VAL_SHIFT		0
 | 
			
		||||
#define B43_NPHY_IQEST_SAMCNT			B43_PHY_N(0x12B) /* I/Q estimate sample count */
 | 
			
		||||
#define B43_NPHY_IQEST_IQACC_LO0		B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_IQACC_HI0		B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_IPACC_LO0		B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_IPACC_HI0		B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_QPACC_LO0		B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_QPACC_HI0		B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
 | 
			
		||||
#define B43_NPHY_IQEST_IQACC_LO1		B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
 | 
			
		||||
#define B43_NPHY_IQEST_IQACC_HI1		B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
 | 
			
		||||
#define B43_NPHY_IQEST_IPACC_LO1		B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
 | 
			
		||||
#define B43_NPHY_IQEST_IPACC_HI1		B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
 | 
			
		||||
#define B43_NPHY_IQEST_QPACC_LO1		B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
 | 
			
		||||
#define B43_NPHY_IQEST_QPACC_HI1		B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
 | 
			
		||||
#define B43_NPHY_MIMO_CRSTXEXT			B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
 | 
			
		||||
#define B43_NPHY_PWRDET1			B43_PHY_N(0x13B) /* Power det 1 */
 | 
			
		||||
#define B43_NPHY_PWRDET2			B43_PHY_N(0x13C) /* Power det 2 */
 | 
			
		||||
#define B43_NPHY_MAXRSSI_DTIME			B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
 | 
			
		||||
#define B43_NPHY_PIL_DW0			B43_PHY_N(0x141) /* Pilot data weight 0 */
 | 
			
		||||
#define B43_NPHY_PIL_DW1			B43_PHY_N(0x142) /* Pilot data weight 1 */
 | 
			
		||||
#define B43_NPHY_PIL_DW2			B43_PHY_N(0x143) /* Pilot data weight 2 */
 | 
			
		||||
#define  B43_NPHY_PIL_DW_BPSK			0x000F /* BPSK */
 | 
			
		||||
#define  B43_NPHY_PIL_DW_BPSK_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_PIL_DW_QPSK			0x00F0 /* QPSK */
 | 
			
		||||
#define  B43_NPHY_PIL_DW_QPSK_SHIFT		4
 | 
			
		||||
#define  B43_NPHY_PIL_DW_16QAM			0x0F00 /* 16-QAM */
 | 
			
		||||
#define  B43_NPHY_PIL_DW_16QAM_SHIFT		8
 | 
			
		||||
#define  B43_NPHY_PIL_DW_64QAM			0xF000 /* 64-QAM */
 | 
			
		||||
#define  B43_NPHY_PIL_DW_64QAM_SHIFT		12
 | 
			
		||||
#define B43_NPHY_FMDEM_CFG			B43_PHY_N(0x144) /* FM demodulation config */
 | 
			
		||||
#define B43_NPHY_PHASETR_A0			B43_PHY_N(0x145) /* Phase track alpha 0 */
 | 
			
		||||
#define B43_NPHY_PHASETR_A1			B43_PHY_N(0x146) /* Phase track alpha 1 */
 | 
			
		||||
#define B43_NPHY_PHASETR_A2			B43_PHY_N(0x147) /* Phase track alpha 2 */
 | 
			
		||||
#define B43_NPHY_PHASETR_B0			B43_PHY_N(0x148) /* Phase track beta 0 */
 | 
			
		||||
#define B43_NPHY_PHASETR_B1			B43_PHY_N(0x149) /* Phase track beta 1 */
 | 
			
		||||
#define B43_NPHY_PHASETR_B2			B43_PHY_N(0x14A) /* Phase track beta 2 */
 | 
			
		||||
#define B43_NPHY_PHASETR_CHG0			B43_PHY_N(0x14B) /* Phase track change 0 */
 | 
			
		||||
#define B43_NPHY_PHASETR_CHG1			B43_PHY_N(0x14C) /* Phase track change 1 */
 | 
			
		||||
#define B43_NPHY_PHASETW_OFF			B43_PHY_N(0x14D) /* Phase track offset */
 | 
			
		||||
#define B43_NPHY_RFCTL_DBG			B43_PHY_N(0x14E) /* RF control debug */
 | 
			
		||||
#define B43_NPHY_CCK_SHIFTB_REF			B43_PHY_N(0x150) /* CCK shiftbits reference var */
 | 
			
		||||
#define B43_NPHY_OVER_DGAIN0			B43_PHY_N(0x152) /* Override digital gain 0 */
 | 
			
		||||
#define B43_NPHY_OVER_DGAIN1			B43_PHY_N(0x153) /* Override digital gain 1 */
 | 
			
		||||
#define  B43_NPHY_OVER_DGAIN_FDGV		0x0007 /* Force digital gain value */
 | 
			
		||||
#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_OVER_DGAIN_FDGEN		0x0008 /* Force digital gain enable */
 | 
			
		||||
#define  B43_NPHY_OVER_DGAIN_CCKDGECV		0xFF00 /* CCK digital gain enable count value */
 | 
			
		||||
#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT	8
 | 
			
		||||
#define B43_NPHY_BIST_STAT4			B43_PHY_N(0x156) /* BIST status 4 */
 | 
			
		||||
#define B43_NPHY_RADAR_MAL			B43_PHY_N(0x157) /* Radar MA length */
 | 
			
		||||
#define B43_NPHY_RADAR_SRCCTL			B43_PHY_N(0x158) /* Radar search control */
 | 
			
		||||
#define B43_NPHY_VLD_DTSIG			B43_PHY_N(0x159) /* VLD data tones sig */
 | 
			
		||||
#define B43_NPHY_VLD_DTDAT			B43_PHY_N(0x15A) /* VLD data tones data */
 | 
			
		||||
#define B43_NPHY_C1_BPHY_RXIQCA0		B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
 | 
			
		||||
#define B43_NPHY_C1_BPHY_RXIQCB0		B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
 | 
			
		||||
#define B43_NPHY_C2_BPHY_RXIQCA1		B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
 | 
			
		||||
#define B43_NPHY_C2_BPHY_RXIQCB1		B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN0			B43_PHY_N(0x160) /* Frequency gain 0 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN1			B43_PHY_N(0x161) /* Frequency gain 1 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN2			B43_PHY_N(0x162) /* Frequency gain 2 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN3			B43_PHY_N(0x163) /* Frequency gain 3 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN4			B43_PHY_N(0x164) /* Frequency gain 4 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN5			B43_PHY_N(0x165) /* Frequency gain 5 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN6			B43_PHY_N(0x166) /* Frequency gain 6 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN7			B43_PHY_N(0x167) /* Frequency gain 7 */
 | 
			
		||||
#define B43_NPHY_FREQGAIN_BYPASS		B43_PHY_N(0x168) /* Frequency gain bypass */
 | 
			
		||||
#define B43_NPHY_TRLOSS				B43_PHY_N(0x169) /* TR loss value */
 | 
			
		||||
#define B43_NPHY_C1_ADCCLIP			B43_PHY_N(0x16A) /* Core 1 ADC clip */
 | 
			
		||||
#define B43_NPHY_C2_ADCCLIP			B43_PHY_N(0x16B) /* Core 2 ADC clip */
 | 
			
		||||
#define B43_NPHY_LTRN_OFFGAIN			B43_PHY_N(0x16F) /* LTRN offset gain */
 | 
			
		||||
#define B43_NPHY_LTRN_OFF			B43_PHY_N(0x170) /* LTRN offset */
 | 
			
		||||
#define B43_NPHY_NRDATAT_WWISE20SIG		B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
 | 
			
		||||
#define B43_NPHY_NRDATAT_WWISE40SIG		B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
 | 
			
		||||
#define B43_NPHY_NRDATAT_TGNSYNC20SIG		B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
 | 
			
		||||
#define B43_NPHY_NRDATAT_TGNSYNC40SIG		B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
 | 
			
		||||
#define B43_NPHY_WWISE_CRCM0			B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
 | 
			
		||||
#define B43_NPHY_WWISE_CRCM1			B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
 | 
			
		||||
#define B43_NPHY_WWISE_CRCM2			B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
 | 
			
		||||
#define B43_NPHY_WWISE_CRCM3			B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
 | 
			
		||||
#define B43_NPHY_WWISE_CRCM4			B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
 | 
			
		||||
#define B43_NPHY_CHANEST_CDDSH			B43_PHY_N(0x17A) /* Channel estimate CDD shift */
 | 
			
		||||
#define B43_NPHY_HTAGC_WCNT			B43_PHY_N(0x17B) /* HT ADC wait counters */
 | 
			
		||||
#define B43_NPHY_SQPARM				B43_PHY_N(0x17C) /* SQ params */
 | 
			
		||||
#define B43_NPHY_MCSDUP6M			B43_PHY_N(0x17D) /* MCS dup 6M */
 | 
			
		||||
#define B43_NPHY_NDATAT_DUP40			B43_PHY_N(0x17E) /* # data tones dup 40 */
 | 
			
		||||
#define B43_NPHY_DUP40_TGNSYNC_CYCD		B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
 | 
			
		||||
#define B43_NPHY_DUP40_GFBL			B43_PHY_N(0x180) /* Dup40 GF format BL address */
 | 
			
		||||
#define B43_NPHY_DUP40_BL			B43_PHY_N(0x181) /* Dup40 format BL address */
 | 
			
		||||
#define B43_NPHY_LEGDUP_FTA			B43_PHY_N(0x182) /* Legacy dup frm table address */
 | 
			
		||||
#define B43_NPHY_PACPROC_DBG			B43_PHY_N(0x183) /* Packet processing debug */
 | 
			
		||||
#define B43_NPHY_PIL_CYC1			B43_PHY_N(0x184) /* Pilot cycle counter 1 */
 | 
			
		||||
#define B43_NPHY_PIL_CYC2			B43_PHY_N(0x185) /* Pilot cycle counter 2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S0A1			B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S0A2			B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S1A1			B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S1A2			B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S2A1			B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S2A2			B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S0B1			B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S0B2			B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S0B3			B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S1B1			B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S1B2			B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S1B3			B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S2B1			B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S2B2			B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_20CO_S2B3			B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S0A1			B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S0A2			B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S1A1			B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S1A2			B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S2A1			B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S2A2			B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S0B1			B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S0B2			B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S0B3			B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S1B1			B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S1B2			B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S1B3			B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S2B1			B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S2B2			B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
 | 
			
		||||
#define B43_NPHY_TXF_40CO_S2B3			B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_RSSI_X		B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_RSSI_Y		B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_RSSI_Z		B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_TBD			B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_PWRDET		B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0I_TSSI			B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_RSSI_X		B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_RSSI_Y		B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_RSSI_Z		B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_TBD			B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_PWRDET		B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
 | 
			
		||||
#define B43_NPHY_RSSIMC_0Q_TSSI			B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_RSSI_X		B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_RSSI_Y		B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_RSSI_Z		B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_TBD			B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_PWRDET		B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1I_TSSI			B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_RSSI_X		B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_RSSI_Y		B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_RSSI_Z		B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_TBD			B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_PWRDET		B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
 | 
			
		||||
#define B43_NPHY_RSSIMC_1Q_TSSI			B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
 | 
			
		||||
#define B43_NPHY_SAMC_WCNT			B43_PHY_N(0x1BC) /* Sample collect wait counter */
 | 
			
		||||
#define B43_NPHY_PTHROUGH_CNT			B43_PHY_N(0x1BD) /* Pass-through counter */
 | 
			
		||||
#define B43_NPHY_LTRN_OFF_G20L			B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
 | 
			
		||||
#define B43_NPHY_LTRN_OFF_20L			B43_PHY_N(0x1C5) /* LTRN offset 20L */
 | 
			
		||||
#define B43_NPHY_LTRN_OFF_G20U			B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
 | 
			
		||||
#define B43_NPHY_LTRN_OFF_20U			B43_PHY_N(0x1C7) /* LTRN offset 20U */
 | 
			
		||||
#define B43_NPHY_DSSSCCK_GAINSL			B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
 | 
			
		||||
#define B43_NPHY_GPIO_LOOUT			B43_PHY_N(0x1C9) /* GPIO low out */
 | 
			
		||||
#define B43_NPHY_GPIO_HIOUT			B43_PHY_N(0x1CA) /* GPIO high out */
 | 
			
		||||
#define B43_NPHY_CRS_CHECK			B43_PHY_N(0x1CB) /* CRS check */
 | 
			
		||||
#define B43_NPHY_ML_LOGSS_RAT			B43_PHY_N(0x1CC) /* ML/logss ratio */
 | 
			
		||||
#define B43_NPHY_DUPSCALE			B43_PHY_N(0x1CD) /* Dup scale */
 | 
			
		||||
#define B43_NPHY_BW1A				B43_PHY_N(0x1CE) /* BW 1A */
 | 
			
		||||
#define B43_NPHY_BW2				B43_PHY_N(0x1CF) /* BW 2 */
 | 
			
		||||
#define B43_NPHY_BW3				B43_PHY_N(0x1D0) /* BW 3 */
 | 
			
		||||
#define B43_NPHY_BW4				B43_PHY_N(0x1D1) /* BW 4 */
 | 
			
		||||
#define B43_NPHY_BW5				B43_PHY_N(0x1D2) /* BW 5 */
 | 
			
		||||
#define B43_NPHY_BW6				B43_PHY_N(0x1D3) /* BW 6 */
 | 
			
		||||
#define B43_NPHY_COALEN0			B43_PHY_N(0x1D4) /* Coarse length 0 */
 | 
			
		||||
#define B43_NPHY_COALEN1			B43_PHY_N(0x1D5) /* Coarse length 1 */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_1U			B43_PHY_N(0x1D6) /* CRS threshold 1 U */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_2U			B43_PHY_N(0x1D7) /* CRS threshold 2 U */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_3U			B43_PHY_N(0x1D8) /* CRS threshold 3 U */
 | 
			
		||||
#define B43_NPHY_CRSCTL_U			B43_PHY_N(0x1D9) /* CRS control U */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_1L			B43_PHY_N(0x1DA) /* CRS threshold 1 L */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_2L			B43_PHY_N(0x1DB) /* CRS threshold 2 L */
 | 
			
		||||
#define B43_NPHY_CRSTHRES_3L			B43_PHY_N(0x1DC) /* CRS threshold 3 L */
 | 
			
		||||
#define B43_NPHY_CRSCTL_L			B43_PHY_N(0x1DD) /* CRS control L */
 | 
			
		||||
#define B43_NPHY_STRA_1U			B43_PHY_N(0x1DE) /* STR address 1 U */
 | 
			
		||||
#define B43_NPHY_STRA_2U			B43_PHY_N(0x1DF) /* STR address 2 U */
 | 
			
		||||
#define B43_NPHY_STRA_1L			B43_PHY_N(0x1E0) /* STR address 1 L */
 | 
			
		||||
#define B43_NPHY_STRA_2L			B43_PHY_N(0x1E1) /* STR address 2 L */
 | 
			
		||||
#define B43_NPHY_CRSCHECK1			B43_PHY_N(0x1E2) /* CRS check 1 */
 | 
			
		||||
#define B43_NPHY_CRSCHECK2			B43_PHY_N(0x1E3) /* CRS check 2 */
 | 
			
		||||
#define B43_NPHY_CRSCHECK3			B43_PHY_N(0x1E4) /* CRS check 3 */
 | 
			
		||||
#define B43_NPHY_JMPSTP0			B43_PHY_N(0x1E5) /* Jump step 0 */
 | 
			
		||||
#define B43_NPHY_JMPSTP1			B43_PHY_N(0x1E6) /* Jump step 1 */
 | 
			
		||||
#define B43_NPHY_TXPCTL_CMD			B43_PHY_N(0x1E7) /* TX power control command */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_CMD_INIT		0x007F /* Init */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_CMD_COEFF		0x2000 /* Power control coefficients */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN		0x4000 /* Hardware TX power control enable */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_CMD_PCTLEN		0x8000 /* TX power control enable */
 | 
			
		||||
#define B43_NPHY_TXPCTL_N			B43_PHY_N(0x1E8) /* TX power control N num */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_N_TSSID		0x00FF /* N TSSI delay */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_N_NPTIL2		0x0700 /* N PT integer log2 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT		8
 | 
			
		||||
#define B43_NPHY_TXPCTL_ITSSI			B43_PHY_N(0x1E9) /* TX power control idle TSSI */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_ITSSI_0		0x003F /* Idle TSSI 0 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_ITSSI_1		0x3F00 /* Idle TSSI 1 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT		8
 | 
			
		||||
#define  B43_NPHY_TXPCTL_ITSSI_BINF		0x8000 /* Raw TSSI offset bin format */
 | 
			
		||||
#define B43_NPHY_TXPCTL_TPWR			B43_PHY_N(0x1EA) /* TX power control target power */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_TPWR_0			0x00FF /* Power 0 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_TPWR_1			0xFF00 /* Power 1 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT		8
 | 
			
		||||
#define B43_NPHY_TXPCTL_BIDX			B43_PHY_N(0x1EB) /* TX power control base index */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_BIDX_0			0x007F /* uC base index 0 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_BIDX_1			0x7F00 /* uC base index 1 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT		8
 | 
			
		||||
#define  B43_NPHY_TXPCTL_BIDX_LOAD		0x8000 /* Load base index */
 | 
			
		||||
#define B43_NPHY_TXPCTL_PIDX			B43_PHY_N(0x1EC) /* TX power control power index */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_PIDX_0			0x007F /* uC power index 0 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_PIDX_1			0x7F00 /* uC power index 1 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT		8
 | 
			
		||||
#define B43_NPHY_C1_TXPCTL_STAT			B43_PHY_N(0x1ED) /* Core 1 TX power control status */
 | 
			
		||||
#define B43_NPHY_C2_TXPCTL_STAT			B43_PHY_N(0x1EE) /* Core 2 TX power control status */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_STAT_EST		0x00FF /* Estimated power */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT		0
 | 
			
		||||
#define  B43_NPHY_TXPCTL_STAT_BIDX		0x7F00 /* Base index */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT	8
 | 
			
		||||
#define  B43_NPHY_TXPCTL_STAT_ESTVALID		0x8000 /* Estimated power valid */
 | 
			
		||||
#define B43_NPHY_SMALLSGS_LEN			B43_PHY_N(0x1EF) /* Small sig gain settle length */
 | 
			
		||||
#define B43_NPHY_PHYSTAT_GAIN0			B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
 | 
			
		||||
#define B43_NPHY_PHYSTAT_GAIN1			B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
 | 
			
		||||
#define B43_NPHY_PHYSTAT_FREQEST		B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
 | 
			
		||||
#define B43_NPHY_PHYSTAT_ADVRET			B43_PHY_N(0x1F3) /* PHY stats ADV retard */
 | 
			
		||||
#define B43_NPHY_PHYLB_MODE			B43_PHY_N(0x1F4) /* PHY loopback mode */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX20_1			B43_PHY_N(0x1F5) /* Tone map index 20/1 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX20_2			B43_PHY_N(0x1F6) /* Tone map index 20/2 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX20_3			B43_PHY_N(0x1F7) /* Tone map index 20/3 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX40_1			B43_PHY_N(0x1F8) /* Tone map index 40/1 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX40_2			B43_PHY_N(0x1F9) /* Tone map index 40/2 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX40_3			B43_PHY_N(0x1FA) /* Tone map index 40/3 */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX40_4			B43_PHY_N(0x1FB) /* Tone map index 40/4 */
 | 
			
		||||
#define B43_NPHY_PILTONE_MIDX1			B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
 | 
			
		||||
#define B43_NPHY_PILTONE_MIDX2			B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
 | 
			
		||||
#define B43_NPHY_PILTONE_MIDX3			B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
 | 
			
		||||
#define B43_NPHY_TXRIFS_FRDEL			B43_PHY_N(0x1FF) /* TX RIFS frame delay */
 | 
			
		||||
#define B43_NPHY_AFESEQ_RX2TX_PUD_40M		B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
 | 
			
		||||
#define B43_NPHY_AFESEQ_TX2RX_PUD_40M		B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
 | 
			
		||||
#define B43_NPHY_AFESEQ_RX2TX_PUD_20M		B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
 | 
			
		||||
#define B43_NPHY_AFESEQ_TX2RX_PUD_20M		B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
 | 
			
		||||
#define B43_NPHY_RX_SIGCTL			B43_PHY_N(0x204) /* RX signal control */
 | 
			
		||||
#define B43_NPHY_RXPIL_CYCNT0			B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
 | 
			
		||||
#define B43_NPHY_RXPIL_CYCNT1			B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
 | 
			
		||||
#define B43_NPHY_RXPIL_CYCNT2			B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
 | 
			
		||||
#define B43_NPHY_AFESEQ_RX2TX_PUD_10M		B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
 | 
			
		||||
#define B43_NPHY_AFESEQ_TX2RX_PUD_10M		B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
 | 
			
		||||
#define B43_NPHY_DSSSCCK_CRSEXTL		B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
 | 
			
		||||
#define B43_NPHY_ML_LOGSS_RATSLOPE		B43_PHY_N(0x20B) /* ML/logss ratio slope */
 | 
			
		||||
#define B43_NPHY_RIFS_SRCTL			B43_PHY_N(0x20C) /* RIFS search timeout length */
 | 
			
		||||
#define B43_NPHY_TXREALFD			B43_PHY_N(0x20D) /* TX real frame delay */
 | 
			
		||||
#define B43_NPHY_HPANT_SWTHRES			B43_PHY_N(0x20E) /* High power antenna switch threshold */
 | 
			
		||||
#define B43_NPHY_EDCRS_ASSTHRES0		B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
 | 
			
		||||
#define B43_NPHY_EDCRS_ASSTHRES1		B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
 | 
			
		||||
#define B43_NPHY_EDCRS_DEASSTHRES0		B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
 | 
			
		||||
#define B43_NPHY_EDCRS_DEASSTHRES1		B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
 | 
			
		||||
#define B43_NPHY_STR_WTIME20U			B43_PHY_N(0x214) /* STR wait time 20U */
 | 
			
		||||
#define B43_NPHY_STR_WTIME20L			B43_PHY_N(0x215) /* STR wait time 20L */
 | 
			
		||||
#define B43_NPHY_TONE_MIDX657M			B43_PHY_N(0x216) /* Tone map index 657M */
 | 
			
		||||
#define B43_NPHY_HTSIGTONES			B43_PHY_N(0x217) /* HT signal tones */
 | 
			
		||||
#define B43_NPHY_RSSI1				B43_PHY_N(0x219) /* RSSI value 1 */
 | 
			
		||||
#define B43_NPHY_RSSI2				B43_PHY_N(0x21A) /* RSSI value 2 */
 | 
			
		||||
#define B43_NPHY_CHAN_ESTHANG			B43_PHY_N(0x21D) /* Channel estimate hang */
 | 
			
		||||
#define B43_NPHY_FINERX2_CGC			B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
 | 
			
		||||
#define  B43_NPHY_FINERX2_CGC_DECGC		0x0008 /* Decode gated clocks */
 | 
			
		||||
#define B43_NPHY_TXPCTL_INIT			B43_PHY_N(0x222) /* TX power controll init */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_INIT_PIDXI1		0x00FF /* Power index init 1 */
 | 
			
		||||
#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT	0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Broadcom 2055 radio registers */
 | 
			
		||||
 | 
			
		||||
#define B2055_GEN_SPARE			0x00 /* GEN spare */
 | 
			
		||||
#define B2055_SP_PINPD			0x02 /* SP PIN PD */
 | 
			
		||||
#define B2055_C1_SP_RSSI		0x03 /* SP RSSI Core 1 */
 | 
			
		||||
#define B2055_C1_SP_PDMISC		0x04 /* SP PD MISC Core 1 */
 | 
			
		||||
#define B2055_C2_SP_RSSI		0x05 /* SP RSSI Core 2 */
 | 
			
		||||
#define B2055_C2_SP_PDMISC		0x06 /* SP PD MISC Core 2 */
 | 
			
		||||
#define B2055_C1_SP_RXGC1		0x07 /* SP RX GC1 Core 1 */
 | 
			
		||||
#define B2055_C1_SP_RXGC2		0x08 /* SP RX GC2 Core 1 */
 | 
			
		||||
#define B2055_C2_SP_RXGC1		0x09 /* SP RX GC1 Core 2 */
 | 
			
		||||
#define B2055_C2_SP_RXGC2		0x0A /* SP RX GC2 Core 2 */
 | 
			
		||||
#define B2055_C1_SP_LPFBWSEL		0x0B /* SP LPF BW select Core 1 */
 | 
			
		||||
#define B2055_C2_SP_LPFBWSEL		0x0C /* SP LPF BW select Core 2 */
 | 
			
		||||
#define B2055_C1_SP_TXGC1		0x0D /* SP TX GC1 Core 1 */
 | 
			
		||||
#define B2055_C1_SP_TXGC2		0x0E /* SP TX GC2 Core 1 */
 | 
			
		||||
#define B2055_C2_SP_TXGC1		0x0F /* SP TX GC1 Core 2 */
 | 
			
		||||
#define B2055_C2_SP_TXGC2		0x10 /* SP TX GC2 Core 2 */
 | 
			
		||||
#define B2055_MASTER1			0x11 /* Master control 1 */
 | 
			
		||||
#define B2055_MASTER2			0x12 /* Master control 2 */
 | 
			
		||||
#define B2055_PD_LGEN			0x13 /* PD LGEN */
 | 
			
		||||
#define B2055_PD_PLLTS			0x14 /* PD PLL TS */
 | 
			
		||||
#define B2055_C1_PD_LGBUF		0x15 /* PD Core 1 LGBUF */
 | 
			
		||||
#define B2055_C1_PD_TX			0x16 /* PD Core 1 TX */
 | 
			
		||||
#define B2055_C1_PD_RXTX		0x17 /* PD Core 1 RXTX */
 | 
			
		||||
#define B2055_C1_PD_RSSIMISC		0x18 /* PD Core 1 RSSI MISC */
 | 
			
		||||
#define B2055_C2_PD_LGBUF		0x19 /* PD Core 2 LGBUF */
 | 
			
		||||
#define B2055_C2_PD_TX			0x1A /* PD Core 2 TX */
 | 
			
		||||
#define B2055_C2_PD_RXTX		0x1B /* PD Core 2 RXTX */
 | 
			
		||||
#define B2055_C2_PD_RSSIMISC		0x1C /* PD Core 2 RSSI MISC */
 | 
			
		||||
#define B2055_PWRDET_LGEN		0x1D /* PWRDET LGEN */
 | 
			
		||||
#define B2055_C1_PWRDET_LGBUF		0x1E /* PWRDET LGBUF Core 1 */
 | 
			
		||||
#define B2055_C1_PWRDET_RXTX		0x1F /* PWRDET RXTX Core 1 */
 | 
			
		||||
#define B2055_C2_PWRDET_LGBUF		0x20 /* PWRDET LGBUF Core 2 */
 | 
			
		||||
#define B2055_C2_PWRDET_RXTX		0x21 /* PWRDET RXTX Core 2 */
 | 
			
		||||
#define B2055_RRCCAL_CS			0x22 /* RRCCAL Control spare */
 | 
			
		||||
#define B2055_RRCCAL_NOPTSEL		0x23 /* RRCCAL N OPT SEL */
 | 
			
		||||
#define B2055_CAL_MISC			0x24 /* CAL MISC */
 | 
			
		||||
#define B2055_CAL_COUT			0x25 /* CAL Counter out */
 | 
			
		||||
#define B2055_CAL_COUT2			0x26 /* CAL Counter out 2 */
 | 
			
		||||
#define B2055_CAL_CVARCTL		0x27 /* CAL CVAR Control */
 | 
			
		||||
#define B2055_CAL_RVARCTL		0x28 /* CAL RVAR Control */
 | 
			
		||||
#define B2055_CAL_LPOCTL		0x29 /* CAL LPO Control */
 | 
			
		||||
#define B2055_CAL_TS			0x2A /* CAL TS */
 | 
			
		||||
#define B2055_CAL_RCCALRTS		0x2B /* CAL RCCAL READ TS */
 | 
			
		||||
#define B2055_CAL_RCALRTS		0x2C /* CAL RCAL READ TS */
 | 
			
		||||
#define B2055_PADDRV			0x2D /* PAD driver */
 | 
			
		||||
#define B2055_XOCTL1			0x2E /* XO Control 1 */
 | 
			
		||||
#define B2055_XOCTL2			0x2F /* XO Control 2 */
 | 
			
		||||
#define B2055_XOREGUL			0x30 /* XO Regulator */
 | 
			
		||||
#define B2055_XOMISC			0x31 /* XO misc */
 | 
			
		||||
#define B2055_PLL_LFC1			0x32 /* PLL LF C1 */
 | 
			
		||||
#define B2055_PLL_CALVTH		0x33 /* PLL CAL VTH */
 | 
			
		||||
#define B2055_PLL_LFC2			0x34 /* PLL LF C2 */
 | 
			
		||||
#define B2055_PLL_REF			0x35 /* PLL reference */
 | 
			
		||||
#define B2055_PLL_LFR1			0x36 /* PLL LF R1 */
 | 
			
		||||
#define B2055_PLL_PFDCP			0x37 /* PLL PFD CP */
 | 
			
		||||
#define B2055_PLL_IDAC_CPOPAMP		0x38 /* PLL IDAC CPOPAMP */
 | 
			
		||||
#define B2055_PLL_CPREG			0x39 /* PLL CP Regulator */
 | 
			
		||||
#define B2055_PLL_RCAL			0x3A /* PLL RCAL */
 | 
			
		||||
#define B2055_RF_PLLMOD0		0x3B /* RF PLL MOD0 */
 | 
			
		||||
#define B2055_RF_PLLMOD1		0x3C /* RF PLL MOD1 */
 | 
			
		||||
#define B2055_RF_MMDIDAC1		0x3D /* RF MMD IDAC 1 */
 | 
			
		||||
#define B2055_RF_MMDIDAC0		0x3E /* RF MMD IDAC 0 */
 | 
			
		||||
#define B2055_RF_MMDSP			0x3F /* RF MMD spare */
 | 
			
		||||
#define B2055_VCO_CAL1			0x40 /* VCO cal 1 */
 | 
			
		||||
#define B2055_VCO_CAL2			0x41 /* VCO cal 2 */
 | 
			
		||||
#define B2055_VCO_CAL3			0x42 /* VCO cal 3 */
 | 
			
		||||
#define B2055_VCO_CAL4			0x43 /* VCO cal 4 */
 | 
			
		||||
#define B2055_VCO_CAL5			0x44 /* VCO cal 5 */
 | 
			
		||||
#define B2055_VCO_CAL6			0x45 /* VCO cal 6 */
 | 
			
		||||
#define B2055_VCO_CAL7			0x46 /* VCO cal 7 */
 | 
			
		||||
#define B2055_VCO_CAL8			0x47 /* VCO cal 8 */
 | 
			
		||||
#define B2055_VCO_CAL9			0x48 /* VCO cal 9 */
 | 
			
		||||
#define B2055_VCO_CAL10			0x49 /* VCO cal 10 */
 | 
			
		||||
#define B2055_VCO_CAL11			0x4A /* VCO cal 11 */
 | 
			
		||||
#define B2055_VCO_CAL12			0x4B /* VCO cal 12 */
 | 
			
		||||
#define B2055_VCO_CAL13			0x4C /* VCO cal 13 */
 | 
			
		||||
#define B2055_VCO_CAL14			0x4D /* VCO cal 14 */
 | 
			
		||||
#define B2055_VCO_CAL15			0x4E /* VCO cal 15 */
 | 
			
		||||
#define B2055_VCO_CAL16			0x4F /* VCO cal 16 */
 | 
			
		||||
#define B2055_VCO_KVCO			0x50 /* VCO KVCO */
 | 
			
		||||
#define B2055_VCO_CAPTAIL		0x51 /* VCO CAP TAIL */
 | 
			
		||||
#define B2055_VCO_IDACVCO		0x52 /* VCO IDAC VCO */
 | 
			
		||||
#define B2055_VCO_REG			0x53 /* VCO Regulator */
 | 
			
		||||
#define B2055_PLL_RFVTH			0x54 /* PLL RF VTH */
 | 
			
		||||
#define B2055_LGBUF_CENBUF		0x55 /* LGBUF CEN BUF */
 | 
			
		||||
#define B2055_LGEN_TUNE1		0x56 /* LGEN tune 1 */
 | 
			
		||||
#define B2055_LGEN_TUNE2		0x57 /* LGEN tune 2 */
 | 
			
		||||
#define B2055_LGEN_IDAC1		0x58 /* LGEN IDAC 1 */
 | 
			
		||||
#define B2055_LGEN_IDAC2		0x59 /* LGEN IDAC 2 */
 | 
			
		||||
#define B2055_LGEN_BIASC		0x5A /* LGEN BIAS counter */
 | 
			
		||||
#define B2055_LGEN_BIASIDAC		0x5B /* LGEN BIAS IDAC */
 | 
			
		||||
#define B2055_LGEN_RCAL			0x5C /* LGEN RCAL */
 | 
			
		||||
#define B2055_LGEN_DIV			0x5D /* LGEN div */
 | 
			
		||||
#define B2055_LGEN_SPARE2		0x5E /* LGEN spare 2 */
 | 
			
		||||
#define B2055_C1_LGBUF_ATUNE		0x5F /* Core 1 LGBUF A tune */
 | 
			
		||||
#define B2055_C1_LGBUF_GTUNE		0x60 /* Core 1 LGBUF G tune */
 | 
			
		||||
#define B2055_C1_LGBUF_DIV		0x61 /* Core 1 LGBUF div */
 | 
			
		||||
#define B2055_C1_LGBUF_AIDAC		0x62 /* Core 1 LGBUF A IDAC */
 | 
			
		||||
#define B2055_C1_LGBUF_GIDAC		0x63 /* Core 1 LGBUF G IDAC */
 | 
			
		||||
#define B2055_C1_LGBUF_IDACFO		0x64 /* Core 1 LGBUF IDAC filter override */
 | 
			
		||||
#define B2055_C1_LGBUF_SPARE		0x65 /* Core 1 LGBUF spare */
 | 
			
		||||
#define B2055_C1_RX_RFSPC1		0x66 /* Core 1 RX RF SPC1 */
 | 
			
		||||
#define B2055_C1_RX_RFR1		0x67 /* Core 1 RX RF reg 1 */
 | 
			
		||||
#define B2055_C1_RX_RFR2		0x68 /* Core 1 RX RF reg 2 */
 | 
			
		||||
#define B2055_C1_RX_RFRCAL		0x69 /* Core 1 RX RF RCAL */
 | 
			
		||||
#define B2055_C1_RX_BB_BLCMP		0x6A /* Core 1 RX Baseband BUFI LPF CMP */
 | 
			
		||||
#define B2055_C1_RX_BB_LPF		0x6B /* Core 1 RX Baseband LPF */
 | 
			
		||||
#define B2055_C1_RX_BB_MIDACHP		0x6C /* Core 1 RX Baseband MIDAC High-pass */
 | 
			
		||||
#define B2055_C1_RX_BB_VGA1IDAC		0x6D /* Core 1 RX Baseband VGA1 IDAC */
 | 
			
		||||
#define B2055_C1_RX_BB_VGA2IDAC		0x6E /* Core 1 RX Baseband VGA2 IDAC */
 | 
			
		||||
#define B2055_C1_RX_BB_VGA3IDAC		0x6F /* Core 1 RX Baseband VGA3 IDAC */
 | 
			
		||||
#define B2055_C1_RX_BB_BUFOCTL		0x70 /* Core 1 RX Baseband BUFO Control */
 | 
			
		||||
#define B2055_C1_RX_BB_RCCALCTL		0x71 /* Core 1 RX Baseband RCCAL Control */
 | 
			
		||||
#define B2055_C1_RX_BB_RSSICTL1		0x72 /* Core 1 RX Baseband RSSI Control 1 */
 | 
			
		||||
#define B2055_C1_RX_BB_RSSICTL2		0x73 /* Core 1 RX Baseband RSSI Control 2 */
 | 
			
		||||
#define B2055_C1_RX_BB_RSSICTL3		0x74 /* Core 1 RX Baseband RSSI Control 3 */
 | 
			
		||||
#define B2055_C1_RX_BB_RSSICTL4		0x75 /* Core 1 RX Baseband RSSI Control 4 */
 | 
			
		||||
#define B2055_C1_RX_BB_RSSICTL5		0x76 /* Core 1 RX Baseband RSSI Control 5 */
 | 
			
		||||
#define B2055_C1_RX_BB_REG		0x77 /* Core 1 RX Baseband Regulator */
 | 
			
		||||
#define B2055_C1_RX_BB_SPARE1		0x78 /* Core 1 RX Baseband spare 1 */
 | 
			
		||||
#define B2055_C1_RX_TXBBRCAL		0x79 /* Core 1 RX TX BB RCAL */
 | 
			
		||||
#define B2055_C1_TX_RF_SPGA		0x7A /* Core 1 TX RF SGM PGA */
 | 
			
		||||
#define B2055_C1_TX_RF_SPAD		0x7B /* Core 1 TX RF SGM PAD */
 | 
			
		||||
#define B2055_C1_TX_RF_CNTPGA1		0x7C /* Core 1 TX RF counter PGA 1 */
 | 
			
		||||
#define B2055_C1_TX_RF_CNTPAD1		0x7D /* Core 1 TX RF counter PAD 1 */
 | 
			
		||||
#define B2055_C1_TX_RF_PGAIDAC		0x7E /* Core 1 TX RF PGA IDAC */
 | 
			
		||||
#define B2055_C1_TX_PGAPADTN		0x7F /* Core 1 TX PGA PAD TN */
 | 
			
		||||
#define B2055_C1_TX_PADIDAC1		0x80 /* Core 1 TX PAD IDAC 1 */
 | 
			
		||||
#define B2055_C1_TX_PADIDAC2		0x81 /* Core 1 TX PAD IDAC 2 */
 | 
			
		||||
#define B2055_C1_TX_MXBGTRIM		0x82 /* Core 1 TX MX B/G TRIM */
 | 
			
		||||
#define B2055_C1_TX_RF_RCAL		0x83 /* Core 1 TX RF RCAL */
 | 
			
		||||
#define B2055_C1_TX_RF_PADTSSI1		0x84 /* Core 1 TX RF PAD TSSI1 */
 | 
			
		||||
#define B2055_C1_TX_RF_PADTSSI2		0x85 /* Core 1 TX RF PAD TSSI2 */
 | 
			
		||||
#define B2055_C1_TX_RF_SPARE		0x86 /* Core 1 TX RF spare */
 | 
			
		||||
#define B2055_C1_TX_RF_IQCAL1		0x87 /* Core 1 TX RF I/Q CAL 1 */
 | 
			
		||||
#define B2055_C1_TX_RF_IQCAL2		0x88 /* Core 1 TX RF I/Q CAL 2 */
 | 
			
		||||
#define B2055_C1_TXBB_RCCAL		0x89 /* Core 1 TXBB RC CAL Control */
 | 
			
		||||
#define B2055_C1_TXBB_LPF1		0x8A /* Core 1 TXBB LPF 1 */
 | 
			
		||||
#define B2055_C1_TX_VOSCNCL		0x8B /* Core 1 TX VOS CNCL */
 | 
			
		||||
#define B2055_C1_TX_LPF_MXGMIDAC	0x8C /* Core 1 TX LPF MXGM IDAC */
 | 
			
		||||
#define B2055_C1_TX_BB_MXGM		0x8D /* Core 1 TX BB MXGM */
 | 
			
		||||
#define B2055_C2_LGBUF_ATUNE		0x8E /* Core 2 LGBUF A tune */
 | 
			
		||||
#define B2055_C2_LGBUF_GTUNE		0x8F /* Core 2 LGBUF G tune */
 | 
			
		||||
#define B2055_C2_LGBUF_DIV		0x90 /* Core 2 LGBUF div */
 | 
			
		||||
#define B2055_C2_LGBUF_AIDAC		0x91 /* Core 2 LGBUF A IDAC */
 | 
			
		||||
#define B2055_C2_LGBUF_GIDAC		0x92 /* Core 2 LGBUF G IDAC */
 | 
			
		||||
#define B2055_C2_LGBUF_IDACFO		0x93 /* Core 2 LGBUF IDAC filter override */
 | 
			
		||||
#define B2055_C2_LGBUF_SPARE		0x94 /* Core 2 LGBUF spare */
 | 
			
		||||
#define B2055_C2_RX_RFSPC1		0x95 /* Core 2 RX RF SPC1 */
 | 
			
		||||
#define B2055_C2_RX_RFR1		0x96 /* Core 2 RX RF reg 1 */
 | 
			
		||||
#define B2055_C2_RX_RFR2		0x97 /* Core 2 RX RF reg 2 */
 | 
			
		||||
#define B2055_C2_RX_RFRCAL		0x98 /* Core 2 RX RF RCAL */
 | 
			
		||||
#define B2055_C2_RX_BB_BLCMP		0x99 /* Core 2 RX Baseband BUFI LPF CMP */
 | 
			
		||||
#define B2055_C2_RX_BB_LPF		0x9A /* Core 2 RX Baseband LPF */
 | 
			
		||||
#define B2055_C2_RX_BB_MIDACHP		0x9B /* Core 2 RX Baseband MIDAC High-pass */
 | 
			
		||||
#define B2055_C2_RX_BB_VGA1IDAC		0x9C /* Core 2 RX Baseband VGA1 IDAC */
 | 
			
		||||
#define B2055_C2_RX_BB_VGA2IDAC		0x9D /* Core 2 RX Baseband VGA2 IDAC */
 | 
			
		||||
#define B2055_C2_RX_BB_VGA3IDAC		0x9E /* Core 2 RX Baseband VGA3 IDAC */
 | 
			
		||||
#define B2055_C2_RX_BB_BUFOCTL		0x9F /* Core 2 RX Baseband BUFO Control */
 | 
			
		||||
#define B2055_C2_RX_BB_RCCALCTL		0xA0 /* Core 2 RX Baseband RCCAL Control */
 | 
			
		||||
#define B2055_C2_RX_BB_RSSICTL1		0xA1 /* Core 2 RX Baseband RSSI Control 1 */
 | 
			
		||||
#define B2055_C2_RX_BB_RSSICTL2		0xA2 /* Core 2 RX Baseband RSSI Control 2 */
 | 
			
		||||
#define B2055_C2_RX_BB_RSSICTL3		0xA3 /* Core 2 RX Baseband RSSI Control 3 */
 | 
			
		||||
#define B2055_C2_RX_BB_RSSICTL4		0xA4 /* Core 2 RX Baseband RSSI Control 4 */
 | 
			
		||||
#define B2055_C2_RX_BB_RSSICTL5		0xA5 /* Core 2 RX Baseband RSSI Control 5 */
 | 
			
		||||
#define B2055_C2_RX_BB_REG		0xA6 /* Core 2 RX Baseband Regulator */
 | 
			
		||||
#define B2055_C2_RX_BB_SPARE1		0xA7 /* Core 2 RX Baseband spare 1 */
 | 
			
		||||
#define B2055_C2_RX_TXBBRCAL		0xA8 /* Core 2 RX TX BB RCAL */
 | 
			
		||||
#define B2055_C2_TX_RF_SPGA		0xA9 /* Core 2 TX RF SGM PGA */
 | 
			
		||||
#define B2055_C2_TX_RF_SPAD		0xAA /* Core 2 TX RF SGM PAD */
 | 
			
		||||
#define B2055_C2_TX_RF_CNTPGA1		0xAB /* Core 2 TX RF counter PGA 1 */
 | 
			
		||||
#define B2055_C2_TX_RF_CNTPAD1		0xAC /* Core 2 TX RF counter PAD 1 */
 | 
			
		||||
#define B2055_C2_TX_RF_PGAIDAC		0xAD /* Core 2 TX RF PGA IDAC */
 | 
			
		||||
#define B2055_C2_TX_PGAPADTN		0xAE /* Core 2 TX PGA PAD TN */
 | 
			
		||||
#define B2055_C2_TX_PADIDAC1		0xAF /* Core 2 TX PAD IDAC 1 */
 | 
			
		||||
#define B2055_C2_TX_PADIDAC2		0xB0 /* Core 2 TX PAD IDAC 2 */
 | 
			
		||||
#define B2055_C2_TX_MXBGTRIM		0xB1 /* Core 2 TX MX B/G TRIM */
 | 
			
		||||
#define B2055_C2_TX_RF_RCAL		0xB2 /* Core 2 TX RF RCAL */
 | 
			
		||||
#define B2055_C2_TX_RF_PADTSSI1		0xB3 /* Core 2 TX RF PAD TSSI1 */
 | 
			
		||||
#define B2055_C2_TX_RF_PADTSSI2		0xB4 /* Core 2 TX RF PAD TSSI2 */
 | 
			
		||||
#define B2055_C2_TX_RF_SPARE		0xB5 /* Core 2 TX RF spare */
 | 
			
		||||
#define B2055_C2_TX_RF_IQCAL1		0xB6 /* Core 2 TX RF I/Q CAL 1 */
 | 
			
		||||
#define B2055_C2_TX_RF_IQCAL2		0xB7 /* Core 2 TX RF I/Q CAL 2 */
 | 
			
		||||
#define B2055_C2_TXBB_RCCAL		0xB8 /* Core 2 TXBB RC CAL Control */
 | 
			
		||||
#define B2055_C2_TXBB_LPF1		0xB9 /* Core 2 TXBB LPF 1 */
 | 
			
		||||
#define B2055_C2_TX_VOSCNCL		0xBA /* Core 2 TX VOS CNCL */
 | 
			
		||||
#define B2055_C2_TX_LPF_MXGMIDAC	0xBB /* Core 2 TX LPF MXGM IDAC */
 | 
			
		||||
#define B2055_C2_TX_BB_MXGM		0xBC /* Core 2 TX BB MXGM */
 | 
			
		||||
#define B2055_PRG_GCHP21		0xBD /* PRG GC HPVGA23 21 */
 | 
			
		||||
#define B2055_PRG_GCHP22		0xBE /* PRG GC HPVGA23 22 */
 | 
			
		||||
#define B2055_PRG_GCHP23		0xBF /* PRG GC HPVGA23 23 */
 | 
			
		||||
#define B2055_PRG_GCHP24		0xC0 /* PRG GC HPVGA23 24 */
 | 
			
		||||
#define B2055_PRG_GCHP25		0xC1 /* PRG GC HPVGA23 25 */
 | 
			
		||||
#define B2055_PRG_GCHP26		0xC2 /* PRG GC HPVGA23 26 */
 | 
			
		||||
#define B2055_PRG_GCHP27		0xC3 /* PRG GC HPVGA23 27 */
 | 
			
		||||
#define B2055_PRG_GCHP28		0xC4 /* PRG GC HPVGA23 28 */
 | 
			
		||||
#define B2055_PRG_GCHP29		0xC5 /* PRG GC HPVGA23 29 */
 | 
			
		||||
#define B2055_PRG_GCHP30		0xC6 /* PRG GC HPVGA23 30 */
 | 
			
		||||
#define B2055_C1_LNA_GAINBST		0xCD /* Core 1 LNA GAINBST */
 | 
			
		||||
#define B2055_C1_B0NB_RSSIVCM		0xD2 /* Core 1 B0 narrow-band RSSI VCM */
 | 
			
		||||
#define B2055_C1_GENSPARE2		0xD6 /* Core 1 GEN spare 2 */
 | 
			
		||||
#define B2055_C2_LNA_GAINBST		0xD9 /* Core 2 LNA GAINBST */
 | 
			
		||||
#define B2055_C2_B0NB_RSSIVCM		0xDE /* Core 2 B0 narrow-band RSSI VCM */
 | 
			
		||||
#define B2055_C2_GENSPARE2		0xE2 /* Core 2 GEN spare 2 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct b43_wldev;
 | 
			
		||||
 | 
			
		||||
int b43_phy_initn(struct b43_wldev *dev);
 | 
			
		||||
 | 
			
		||||
void b43_nphy_radio_turn_on(struct b43_wldev *dev);
 | 
			
		||||
void b43_nphy_radio_turn_off(struct b43_wldev *dev);
 | 
			
		||||
 | 
			
		||||
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
 | 
			
		||||
 | 
			
		||||
void b43_nphy_xmitpower(struct b43_wldev *dev);
 | 
			
		||||
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
 | 
			
		||||
 | 
			
		||||
#endif /* B43_NPHY_H_ */
 | 
			
		||||
@ -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_ */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2476
									
								
								package/b43/src/tables_nphy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2476
									
								
								package/b43/src/tables_nphy.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										159
									
								
								package/b43/src/tables_nphy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								package/b43/src/tables_nphy.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,159 @@
 | 
			
		||||
#ifndef B43_TABLES_NPHY_H_
 | 
			
		||||
#define B43_TABLES_NPHY_H_
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct b43_nphy_channeltab_entry {
 | 
			
		||||
	/* The channel number */
 | 
			
		||||
	u8 channel;
 | 
			
		||||
	/* Radio register values on channelswitch */
 | 
			
		||||
	u8 radio_pll_ref;
 | 
			
		||||
	u8 radio_rf_pllmod0;
 | 
			
		||||
	u8 radio_rf_pllmod1;
 | 
			
		||||
	u8 radio_vco_captail;
 | 
			
		||||
	u8 radio_vco_cal1;
 | 
			
		||||
	u8 radio_vco_cal2;
 | 
			
		||||
	u8 radio_pll_lfc1;
 | 
			
		||||
	u8 radio_pll_lfr1;
 | 
			
		||||
	u8 radio_pll_lfc2;
 | 
			
		||||
	u8 radio_lgbuf_cenbuf;
 | 
			
		||||
	u8 radio_lgen_tune1;
 | 
			
		||||
	u8 radio_lgen_tune2;
 | 
			
		||||
	u8 radio_c1_lgbuf_atune;
 | 
			
		||||
	u8 radio_c1_lgbuf_gtune;
 | 
			
		||||
	u8 radio_c1_rx_rfr1;
 | 
			
		||||
	u8 radio_c1_tx_pgapadtn;
 | 
			
		||||
	u8 radio_c1_tx_mxbgtrim;
 | 
			
		||||
	u8 radio_c2_lgbuf_atune;
 | 
			
		||||
	u8 radio_c2_lgbuf_gtune;
 | 
			
		||||
	u8 radio_c2_rx_rfr1;
 | 
			
		||||
	u8 radio_c2_tx_pgapadtn;
 | 
			
		||||
	u8 radio_c2_tx_mxbgtrim;
 | 
			
		||||
	/* PHY register values on channelswitch */
 | 
			
		||||
	u16 phy_bw1a;
 | 
			
		||||
	u16 phy_bw2;
 | 
			
		||||
	u16 phy_bw3;
 | 
			
		||||
	u16 phy_bw4;
 | 
			
		||||
	u16 phy_bw5;
 | 
			
		||||
	u16 phy_bw6;
 | 
			
		||||
	/* The channel frequency in MHz */
 | 
			
		||||
	u16 freq;
 | 
			
		||||
	/* An unknown value */
 | 
			
		||||
	u16 unk2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct b43_wldev;
 | 
			
		||||
 | 
			
		||||
/* Upload the default register value table.
 | 
			
		||||
 * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
 | 
			
		||||
 * table is uploaded. If "ignore_uploadflag" is true, we upload any value
 | 
			
		||||
 * and ignore the "UPLOAD" flag. */
 | 
			
		||||
void b2055_upload_inittab(struct b43_wldev *dev,
 | 
			
		||||
			  bool ghz5, bool ignore_uploadflag);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Get the NPHY Channel Switch Table entry for a channel number.
 | 
			
		||||
 * Returns NULL on failure to find an entry. */
 | 
			
		||||
const struct b43_nphy_channeltab_entry *
 | 
			
		||||
b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The N-PHY tables. */
 | 
			
		||||
 | 
			
		||||
#define B43_NTAB_TYPEMASK		0xF0000000
 | 
			
		||||
#define B43_NTAB_8BIT			0x10000000
 | 
			
		||||
#define B43_NTAB_16BIT			0x20000000
 | 
			
		||||
#define B43_NTAB_32BIT			0x30000000
 | 
			
		||||
#define B43_NTAB8(table, offset)	(((table) << 10) | (offset) | B43_NTAB_8BIT)
 | 
			
		||||
#define B43_NTAB16(table, offset)	(((table) << 10) | (offset) | B43_NTAB_16BIT)
 | 
			
		||||
#define B43_NTAB32(table, offset)	(((table) << 10) | (offset) | B43_NTAB_32BIT)
 | 
			
		||||
 | 
			
		||||
/* Static N-PHY tables */
 | 
			
		||||
#define B43_NTAB_FRAMESTRUCT		B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */
 | 
			
		||||
#define B43_NTAB_FRAMESTRUCT_SIZE	832
 | 
			
		||||
#define B43_NTAB_FRAMELT		B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */
 | 
			
		||||
#define B43_NTAB_FRAMELT_SIZE		32
 | 
			
		||||
#define B43_NTAB_TMAP			B43_NTAB32(0x0C, 0x000) /* T Map Table */
 | 
			
		||||
#define B43_NTAB_TMAP_SIZE		448
 | 
			
		||||
#define B43_NTAB_TDTRN			B43_NTAB32(0x0E, 0x000) /* TDTRN Table */
 | 
			
		||||
#define B43_NTAB_TDTRN_SIZE		704
 | 
			
		||||
#define B43_NTAB_INTLEVEL		B43_NTAB32(0x0D, 0x000) /* Int Level Table */
 | 
			
		||||
#define B43_NTAB_INTLEVEL_SIZE		7
 | 
			
		||||
#define B43_NTAB_PILOT			B43_NTAB16(0x0B, 0x000) /* Pilot Table */
 | 
			
		||||
#define B43_NTAB_PILOT_SIZE		88
 | 
			
		||||
#define B43_NTAB_PILOTLT		B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */
 | 
			
		||||
#define B43_NTAB_PILOTLT_SIZE		6
 | 
			
		||||
#define B43_NTAB_TDI20A0		B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */
 | 
			
		||||
#define B43_NTAB_TDI20A0_SIZE		55
 | 
			
		||||
#define B43_NTAB_TDI20A1		B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */
 | 
			
		||||
#define B43_NTAB_TDI20A1_SIZE		55
 | 
			
		||||
#define B43_NTAB_TDI40A0		B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */
 | 
			
		||||
#define B43_NTAB_TDI40A0_SIZE		110
 | 
			
		||||
#define B43_NTAB_TDI40A1		B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */
 | 
			
		||||
#define B43_NTAB_TDI40A1_SIZE		110
 | 
			
		||||
#define B43_NTAB_BDI			B43_NTAB16(0x15, 0x000) /* BDI Table */
 | 
			
		||||
#define B43_NTAB_BDI_SIZE		6
 | 
			
		||||
#define B43_NTAB_CHANEST		B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */
 | 
			
		||||
#define B43_NTAB_CHANEST_SIZE		96
 | 
			
		||||
#define B43_NTAB_MCS			B43_NTAB8 (0x12, 0x000) /* MCS Table */
 | 
			
		||||
#define B43_NTAB_MCS_SIZE		128
 | 
			
		||||
 | 
			
		||||
/* Volatile N-PHY tables */
 | 
			
		||||
#define B43_NTAB_NOISEVAR10		B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */
 | 
			
		||||
#define B43_NTAB_NOISEVAR10_SIZE	256
 | 
			
		||||
#define B43_NTAB_NOISEVAR11		B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */
 | 
			
		||||
#define B43_NTAB_NOISEVAR11_SIZE	256
 | 
			
		||||
#define B43_NTAB_C0_ESTPLT		B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */
 | 
			
		||||
#define B43_NTAB_C0_ESTPLT_SIZE		64
 | 
			
		||||
#define B43_NTAB_C1_ESTPLT		B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
 | 
			
		||||
#define B43_NTAB_C1_ESTPLT_SIZE		64
 | 
			
		||||
#define B43_NTAB_C0_ADJPLT		B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */
 | 
			
		||||
#define B43_NTAB_C0_ADJPLT_SIZE		128
 | 
			
		||||
#define B43_NTAB_C1_ADJPLT		B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
 | 
			
		||||
#define B43_NTAB_C1_ADJPLT_SIZE		128
 | 
			
		||||
#define B43_NTAB_C0_GAINCTL		B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */
 | 
			
		||||
#define B43_NTAB_C0_GAINCTL_SIZE	128
 | 
			
		||||
#define B43_NTAB_C1_GAINCTL		B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
 | 
			
		||||
#define B43_NTAB_C1_GAINCTL_SIZE	128
 | 
			
		||||
#define B43_NTAB_C0_IQLT		B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */
 | 
			
		||||
#define B43_NTAB_C0_IQLT_SIZE		128
 | 
			
		||||
#define B43_NTAB_C1_IQLT		B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
 | 
			
		||||
#define B43_NTAB_C1_IQLT_SIZE		128
 | 
			
		||||
#define B43_NTAB_C0_LOFEEDTH		B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */
 | 
			
		||||
#define B43_NTAB_C0_LOFEEDTH_SIZE	128
 | 
			
		||||
#define B43_NTAB_C1_LOFEEDTH		B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
 | 
			
		||||
#define B43_NTAB_C1_LOFEEDTH_SIZE	128
 | 
			
		||||
 | 
			
		||||
void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
 | 
			
		||||
 | 
			
		||||
extern const u8 b43_ntab_adjustpower0[];
 | 
			
		||||
extern const u8 b43_ntab_adjustpower1[];
 | 
			
		||||
extern const u16 b43_ntab_bdi[];
 | 
			
		||||
extern const u32 b43_ntab_channelest[];
 | 
			
		||||
extern const u8 b43_ntab_estimatepowerlt0[];
 | 
			
		||||
extern const u8 b43_ntab_estimatepowerlt1[];
 | 
			
		||||
extern const u8 b43_ntab_framelookup[];
 | 
			
		||||
extern const u32 b43_ntab_framestruct[];
 | 
			
		||||
extern const u32 b43_ntab_gainctl0[];
 | 
			
		||||
extern const u32 b43_ntab_gainctl1[];
 | 
			
		||||
extern const u32 b43_ntab_intlevel[];
 | 
			
		||||
extern const u32 b43_ntab_iqlt0[];
 | 
			
		||||
extern const u32 b43_ntab_iqlt1[];
 | 
			
		||||
extern const u16 b43_ntab_loftlt0[];
 | 
			
		||||
extern const u16 b43_ntab_loftlt1[];
 | 
			
		||||
extern const u8 b43_ntab_mcs[];
 | 
			
		||||
extern const u32 b43_ntab_noisevar10[];
 | 
			
		||||
extern const u32 b43_ntab_noisevar11[];
 | 
			
		||||
extern const u16 b43_ntab_pilot[];
 | 
			
		||||
extern const u32 b43_ntab_pilotlt[];
 | 
			
		||||
extern const u32 b43_ntab_tdi20a0[];
 | 
			
		||||
extern const u32 b43_ntab_tdi20a1[];
 | 
			
		||||
extern const u32 b43_ntab_tdi40a0[];
 | 
			
		||||
extern const u32 b43_ntab_tdi40a1[];
 | 
			
		||||
extern const u32 b43_ntab_tdtrn[];
 | 
			
		||||
extern const u32 b43_ntab_tmap[];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* B43_TABLES_NPHY_H_ */
 | 
			
		||||
							
								
								
									
										674
									
								
								package/b43/src/wa.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										674
									
								
								package/b43/src/wa.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,674 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Broadcom B43 wireless driver
 | 
			
		||||
 | 
			
		||||
  PHY workarounds.
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
 | 
			
		||||
  Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
 | 
			
		||||
 | 
			
		||||
  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
  it under the terms of the GNU General Public License as published by
 | 
			
		||||
  the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
  (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
  This program is distributed in the hope that it will be useful,
 | 
			
		||||
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
  GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
  You should have received a copy of the GNU General Public License
 | 
			
		||||
  along with this program; see the file COPYING.  If not, write to
 | 
			
		||||
  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 | 
			
		||||
  Boston, MA 02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "b43.h"
 | 
			
		||||
#include "main.h"
 | 
			
		||||
#include "tables.h"
 | 
			
		||||
#include "phy.h"
 | 
			
		||||
#include "wa.h"
 | 
			
		||||
 | 
			
		||||
static void b43_wa_papd(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	u16 backup;
 | 
			
		||||
 | 
			
		||||
	backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
 | 
			
		||||
	b43_dummy_transmission(dev);
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_auxclipthr(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_afcdac(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, 0x0035, 0x03FF);
 | 
			
		||||
	b43_phy_write(dev, 0x0036, 0x0400);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_txdc_offset(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void b43_wa_initgains(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_LPFGAINCTL,
 | 
			
		||||
		b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F);
 | 
			
		||||
	if (phy->rev <= 2)
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF);
 | 
			
		||||
	b43_radio_write16(dev, 0x0002, 0x1FBF);
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, 0x0024, 0x4680);
 | 
			
		||||
	b43_phy_write(dev, 0x0020, 0x0003);
 | 
			
		||||
	b43_phy_write(dev, 0x001D, 0x0F40);
 | 
			
		||||
	b43_phy_write(dev, 0x001F, 0x1C00);
 | 
			
		||||
	if (phy->rev <= 3)
 | 
			
		||||
		b43_phy_write(dev, 0x002A,
 | 
			
		||||
			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400);
 | 
			
		||||
	else if (phy->rev == 5) {
 | 
			
		||||
		b43_phy_write(dev, 0x002A,
 | 
			
		||||
			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00);
 | 
			
		||||
		b43_phy_write(dev, 0x00CC, 0x2121);
 | 
			
		||||
	}
 | 
			
		||||
	if (phy->rev >= 3)
 | 
			
		||||
		b43_phy_write(dev, 0x00BA, 0x3ED5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_divider(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100);
 | 
			
		||||
	b43_phy_write(dev, 0x008E, 0x58C1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */
 | 
			
		||||
{
 | 
			
		||||
	if (dev->phy.rev <= 2) {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (0 /* FIXME: For APHY.rev=2 this might be needed */) {
 | 
			
		||||
		for (i = 0; i < 8; i++)
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8);
 | 
			
		||||
		for (i = 8; i < 16; i++)
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8);
 | 
			
		||||
	} else {
 | 
			
		||||
		for (i = 0; i < 64; i++)
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_analog(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	u16 ofdmrev;
 | 
			
		||||
 | 
			
		||||
	ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION;
 | 
			
		||||
	if (ofdmrev > 2) {
 | 
			
		||||
		if (phy->type == B43_PHYTYPE_A)
 | 
			
		||||
			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808);
 | 
			
		||||
		else
 | 
			
		||||
			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_dac(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->phy.analog == 1)
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
 | 
			
		||||
			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008);
 | 
			
		||||
	else
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
 | 
			
		||||
			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (dev->phy.type == B43_PHYTYPE_A)
 | 
			
		||||
		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]);
 | 
			
		||||
	else
 | 
			
		||||
		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (phy->type == B43_PHYTYPE_A) {
 | 
			
		||||
		if (phy->rev == 2)
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]);
 | 
			
		||||
		else
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (phy->rev == 1)
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]);
 | 
			
		||||
		else
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
 | 
			
		||||
		b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (phy->type == B43_PHYTYPE_A) {
 | 
			
		||||
		if (phy->rev <= 1)
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
							i, 0);
 | 
			
		||||
		else if (phy->rev == 2)
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
							i, b43_tab_noisescalea2[i]);
 | 
			
		||||
		else if (phy->rev == 3)
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
							i, b43_tab_noisescalea3[i]);
 | 
			
		||||
		else
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
							i, b43_tab_noisescaleg3[i]);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (phy->rev >= 6) {
 | 
			
		||||
			if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
 | 
			
		||||
				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
						i, b43_tab_noisescaleg3[i]);
 | 
			
		||||
			else
 | 
			
		||||
				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
						i, b43_tab_noisescaleg2[i]);
 | 
			
		||||
		} else {
 | 
			
		||||
			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
 | 
			
		||||
							i, b43_tab_noisescaleg1[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
 | 
			
		||||
			b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD,
 | 
			
		||||
				i, b43_tab_retard[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_txlna_gain(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_crs_reset(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, 0x002C, 0x0064);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_2060txlna_gain(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_hf_write(dev, b43_hf_read(dev) |
 | 
			
		||||
			 B43_HF_2060W);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_lms(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, 0x0055,
 | 
			
		||||
		(b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_mixedsignal(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
	int i;
 | 
			
		||||
	const u16 *tab;
 | 
			
		||||
 | 
			
		||||
	if (phy->type == B43_PHYTYPE_A) {
 | 
			
		||||
		tab = b43_tab_sigmasqr1;
 | 
			
		||||
	} else if (phy->type == B43_PHYTYPE_G) {
 | 
			
		||||
		tab = b43_tab_sigmasqr2;
 | 
			
		||||
	} else {
 | 
			
		||||
		B43_WARN_ON(1);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ,
 | 
			
		||||
					i, tab[i]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_iqadc(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->phy.analog == 4)
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0,
 | 
			
		||||
			b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_crs_ed(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
 | 
			
		||||
	if (phy->rev == 1) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19);
 | 
			
		||||
	} else if (phy->rev == 2) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_ANTDWELL,
 | 
			
		||||
				  b43_phy_read(dev, B43_PHY_ANTDWELL)
 | 
			
		||||
				  | 0x0800);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_ANTDWELL,
 | 
			
		||||
				  b43_phy_read(dev, B43_PHY_ANTDWELL)
 | 
			
		||||
				  | 0x0800);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_crs_thr(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_CRS0,
 | 
			
		||||
			(b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_crs_blank(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_cck_shiftbits(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_wrssi_offset(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (dev->phy.rev == 1) {
 | 
			
		||||
		for (i = 0; i < 16; i++) {
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1,
 | 
			
		||||
						i, 0x0020);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (i = 0; i < 32; i++) {
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI,
 | 
			
		||||
						i, 0x0820);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15);
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_altagc(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
 | 
			
		||||
	if (phy->rev == 1) {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_LMS, 4);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_ANTWRSETT,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300);
 | 
			
		||||
	b43_radio_write16(dev, 0x7A,
 | 
			
		||||
		b43_radio_read16(dev, 0x7A) | 0x0008);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_N1P1GAIN,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_P1P2GAIN,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_N1N2GAIN,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_N1P1GAIN,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100);
 | 
			
		||||
	if (phy->rev == 1) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_N1N2GAIN,
 | 
			
		||||
				  (b43_phy_read(dev, B43_PHY_N1N2GAIN)
 | 
			
		||||
				   & ~0x000F) | 0x0007);
 | 
			
		||||
	}
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x88),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x88),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x96),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x89),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x89),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x82),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x96),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x81),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x81),
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00);
 | 
			
		||||
	if (phy->rev == 1) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
 | 
			
		||||
			(b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
 | 
			
		||||
			b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_LPFGAINCTL,
 | 
			
		||||
			(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004);
 | 
			
		||||
		if (phy->rev >= 6) {
 | 
			
		||||
			b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
 | 
			
		||||
			b43_phy_write(dev, B43_PHY_LPFGAINCTL,
 | 
			
		||||
				(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_DIVSRCHIDX,
 | 
			
		||||
		(b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874);
 | 
			
		||||
	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00);
 | 
			
		||||
	if (phy->rev == 1) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_DIVP1P2GAIN,
 | 
			
		||||
			(b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_ANTWRSETT,
 | 
			
		||||
			(b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28);
 | 
			
		||||
	} else {
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28);
 | 
			
		||||
	}
 | 
			
		||||
	if (phy->rev >= 6) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x26),
 | 
			
		||||
			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_OFDM(0x26),
 | 
			
		||||
			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000);
 | 
			
		||||
	}
 | 
			
		||||
	b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */
 | 
			
		||||
{
 | 
			
		||||
	b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_cpll_nonpilot(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0);
 | 
			
		||||
	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_rssi_adc(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (dev->phy.analog == 4)
 | 
			
		||||
		b43_phy_write(dev, 0x00DC, 0x7454);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_boards_a(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ssb_bus *bus = dev->dev->bus;
 | 
			
		||||
 | 
			
		||||
	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
 | 
			
		||||
	    bus->boardinfo.type == SSB_BOARD_BU4306 &&
 | 
			
		||||
	    bus->boardinfo.rev < 0x30) {
 | 
			
		||||
		b43_phy_write(dev, 0x0010, 0xE000);
 | 
			
		||||
		b43_phy_write(dev, 0x0013, 0x0140);
 | 
			
		||||
		b43_phy_write(dev, 0x0014, 0x0280);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (bus->boardinfo.type == SSB_BOARD_MP4318 &&
 | 
			
		||||
		    bus->boardinfo.rev < 0x20) {
 | 
			
		||||
			b43_phy_write(dev, 0x0013, 0x0210);
 | 
			
		||||
			b43_phy_write(dev, 0x0014, 0x0840);
 | 
			
		||||
		} else {
 | 
			
		||||
			b43_phy_write(dev, 0x0013, 0x0140);
 | 
			
		||||
			b43_phy_write(dev, 0x0014, 0x0280);
 | 
			
		||||
		}
 | 
			
		||||
		if (dev->phy.rev <= 4)
 | 
			
		||||
			b43_phy_write(dev, 0x0010, 0xE000);
 | 
			
		||||
		else
 | 
			
		||||
			b43_phy_write(dev, 0x0010, 0x2000);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039);
 | 
			
		||||
		b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void b43_wa_boards_g(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ssb_bus *bus = dev->dev->bus;
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
 | 
			
		||||
	if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
 | 
			
		||||
	    bus->boardinfo.type != SSB_BOARD_BU4306 ||
 | 
			
		||||
	    bus->boardinfo.rev != 0x17) {
 | 
			
		||||
		if (phy->rev < 2) {
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002);
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001);
 | 
			
		||||
		} else {
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002);
 | 
			
		||||
			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
 | 
			
		||||
			if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
 | 
			
		||||
			    (phy->rev >= 7)) {
 | 
			
		||||
				b43_phy_write(dev, B43_PHY_EXTG(0x11),
 | 
			
		||||
					b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000);
 | 
			
		||||
				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (bus->sprom.boardflags_lo & B43_BFL_FEM) {
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120);
 | 
			
		||||
		b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void b43_wa_all(struct b43_wldev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct b43_phy *phy = &dev->phy;
 | 
			
		||||
 | 
			
		||||
	if (phy->type == B43_PHYTYPE_A) {
 | 
			
		||||
		switch (phy->rev) {
 | 
			
		||||
		case 2:
 | 
			
		||||
			b43_wa_papd(dev);
 | 
			
		||||
			b43_wa_auxclipthr(dev);
 | 
			
		||||
			b43_wa_afcdac(dev);
 | 
			
		||||
			b43_wa_txdc_offset(dev);
 | 
			
		||||
			b43_wa_initgains(dev);
 | 
			
		||||
			b43_wa_divider(dev);
 | 
			
		||||
			b43_wa_gt(dev);
 | 
			
		||||
			b43_wa_rssi_lt(dev);
 | 
			
		||||
			b43_wa_analog(dev);
 | 
			
		||||
			b43_wa_dac(dev);
 | 
			
		||||
			b43_wa_fft(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_rt(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_art(dev);
 | 
			
		||||
			b43_wa_txlna_gain(dev);
 | 
			
		||||
			b43_wa_crs_reset(dev);
 | 
			
		||||
			b43_wa_2060txlna_gain(dev);
 | 
			
		||||
			b43_wa_lms(dev);
 | 
			
		||||
			break;
 | 
			
		||||
		case 3:
 | 
			
		||||
			b43_wa_papd(dev);
 | 
			
		||||
			b43_wa_mixedsignal(dev);
 | 
			
		||||
			b43_wa_rssi_lt(dev);
 | 
			
		||||
			b43_wa_txdc_offset(dev);
 | 
			
		||||
			b43_wa_initgains(dev);
 | 
			
		||||
			b43_wa_dac(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_msst(dev);
 | 
			
		||||
			b43_wa_analog(dev);
 | 
			
		||||
			b43_wa_gt(dev);
 | 
			
		||||
			b43_wa_txpuoff_rxpuon(dev);
 | 
			
		||||
			b43_wa_txlna_gain(dev);
 | 
			
		||||
			break;
 | 
			
		||||
		case 5:
 | 
			
		||||
			b43_wa_iqadc(dev);
 | 
			
		||||
		case 6:
 | 
			
		||||
			b43_wa_papd(dev);
 | 
			
		||||
			b43_wa_rssi_lt(dev);
 | 
			
		||||
			b43_wa_txdc_offset(dev);
 | 
			
		||||
			b43_wa_initgains(dev);
 | 
			
		||||
			b43_wa_dac(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_msst(dev);
 | 
			
		||||
			b43_wa_analog(dev);
 | 
			
		||||
			b43_wa_gt(dev);
 | 
			
		||||
			b43_wa_txpuoff_rxpuon(dev);
 | 
			
		||||
			b43_wa_txlna_gain(dev);
 | 
			
		||||
			break;
 | 
			
		||||
		case 7:
 | 
			
		||||
			b43_wa_iqadc(dev);
 | 
			
		||||
			b43_wa_papd(dev);
 | 
			
		||||
			b43_wa_rssi_lt(dev);
 | 
			
		||||
			b43_wa_txdc_offset(dev);
 | 
			
		||||
			b43_wa_initgains(dev);
 | 
			
		||||
			b43_wa_dac(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_msst(dev);
 | 
			
		||||
			b43_wa_analog(dev);
 | 
			
		||||
			b43_wa_gt(dev);
 | 
			
		||||
			b43_wa_txpuoff_rxpuon(dev);
 | 
			
		||||
			b43_wa_txlna_gain(dev);
 | 
			
		||||
			b43_wa_rssi_adc(dev);
 | 
			
		||||
		default:
 | 
			
		||||
			B43_WARN_ON(1);
 | 
			
		||||
		}
 | 
			
		||||
		b43_wa_boards_a(dev);
 | 
			
		||||
	} else if (phy->type == B43_PHYTYPE_G) {
 | 
			
		||||
		switch (phy->rev) {
 | 
			
		||||
		case 1://XXX review rev1
 | 
			
		||||
			b43_wa_crs_ed(dev);
 | 
			
		||||
			b43_wa_crs_thr(dev);
 | 
			
		||||
			b43_wa_crs_blank(dev);
 | 
			
		||||
			b43_wa_cck_shiftbits(dev);
 | 
			
		||||
			b43_wa_fft(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_rt(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_art(dev);
 | 
			
		||||
			b43_wa_wrssi_offset(dev);
 | 
			
		||||
			b43_wa_altagc(dev);
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
		case 6:
 | 
			
		||||
		case 7:
 | 
			
		||||
		case 8:
 | 
			
		||||
		case 9:
 | 
			
		||||
			b43_wa_tr_ltov(dev);
 | 
			
		||||
			b43_wa_crs_ed(dev);
 | 
			
		||||
			b43_wa_rssi_lt(dev);
 | 
			
		||||
			b43_wa_nft(dev);
 | 
			
		||||
			b43_wa_nst(dev);
 | 
			
		||||
			b43_wa_msst(dev);
 | 
			
		||||
			b43_wa_wrssi_offset(dev);
 | 
			
		||||
			b43_wa_altagc(dev);
 | 
			
		||||
			b43_wa_analog(dev);
 | 
			
		||||
			b43_wa_txpuoff_rxpuon(dev);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			B43_WARN_ON(1);
 | 
			
		||||
		}
 | 
			
		||||
		b43_wa_boards_g(dev);
 | 
			
		||||
	} else { /* No N PHY support so far */
 | 
			
		||||
		B43_WARN_ON(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b43_wa_cpll_nonpilot(dev);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								package/b43/src/wa.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								package/b43/src/wa.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#ifndef B43_WA_H_
 | 
			
		||||
#define B43_WA_H_
 | 
			
		||||
 | 
			
		||||
void b43_wa_initgains(struct b43_wldev *dev);
 | 
			
		||||
void b43_wa_all(struct b43_wldev *dev);
 | 
			
		||||
 | 
			
		||||
#endif /* B43_WA_H_ */
 | 
			
		||||
@ -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
 | 
			
		||||
							
								
								
									
										231
									
								
								package/mac80211/patches/001-port-to-2.6.23.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								package/mac80211/patches/001-port-to-2.6.23.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,231 @@
 | 
			
		||||
Index: mac80211/net/mac80211/ieee80211.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/ieee80211.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/ieee80211.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -21,7 +21,6 @@
 | 
			
		||||
 #include <linux/wireless.h>
 | 
			
		||||
 #include <linux/rtnetlink.h>
 | 
			
		||||
 #include <linux/bitmap.h>
 | 
			
		||||
-#include <net/net_namespace.h>
 | 
			
		||||
 #include <net/cfg80211.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "ieee80211_i.h"
 | 
			
		||||
@@ -36,6 +35,15 @@
 | 
			
		||||
 
 | 
			
		||||
 #define SUPP_MCS_SET_LEN 16
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+char *print_mac(char *buf, const u8 *addr)
 | 
			
		||||
+{
 | 
			
		||||
+	sprintf(buf, MAC_FMT,
 | 
			
		||||
+		addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
 | 
			
		||||
+	return buf;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
 /*
 | 
			
		||||
  * For seeing transmitted packets on monitor interfaces
 | 
			
		||||
  * we have a radiotap header too.
 | 
			
		||||
@@ -48,11 +56,13 @@ struct ieee80211_tx_status_rtap_hdr {
 | 
			
		||||
 
 | 
			
		||||
 /* common interface routines */
 | 
			
		||||
 
 | 
			
		||||
+#if 0
 | 
			
		||||
 static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
 | 
			
		||||
 {
 | 
			
		||||
 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 | 
			
		||||
 	return ETH_ALEN;
 | 
			
		||||
 }
 | 
			
		||||
+#endif
 | 
			
		||||
 
 | 
			
		||||
 /* must be called under mdev tx lock */
 | 
			
		||||
 static void ieee80211_configure_filter(struct ieee80211_local *local)
 | 
			
		||||
@@ -800,6 +810,7 @@ static void ieee80211_set_multicast_list
 | 
			
		||||
 	dev_mc_sync(local->mdev, dev);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+#if 0
 | 
			
		||||
 static const struct header_ops ieee80211_header_ops = {
 | 
			
		||||
 	.create		= eth_header,
 | 
			
		||||
 	.parse		= header_parse_80211,
 | 
			
		||||
@@ -807,6 +818,7 @@ static const struct header_ops ieee80211
 | 
			
		||||
 	.cache		= eth_header_cache,
 | 
			
		||||
 	.cache_update	= eth_header_cache_update,
 | 
			
		||||
 };
 | 
			
		||||
+#endif
 | 
			
		||||
 
 | 
			
		||||
 /* Must not be called for mdev */
 | 
			
		||||
 void ieee80211_if_setup(struct net_device *dev)
 | 
			
		||||
@@ -1455,7 +1467,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 | 
			
		||||
 	mdev->open = ieee80211_master_open;
 | 
			
		||||
 	mdev->stop = ieee80211_master_stop;
 | 
			
		||||
 	mdev->type = ARPHRD_IEEE80211;
 | 
			
		||||
-	mdev->header_ops = &ieee80211_header_ops;
 | 
			
		||||
+//	mdev->header_ops = &ieee80211_header_ops;
 | 
			
		||||
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 | 
			
		||||
 
 | 
			
		||||
 	sdata->vif.type = IEEE80211_IF_TYPE_AP;
 | 
			
		||||
Index: mac80211/net/mac80211/ieee80211_i.h
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/ieee80211_i.h	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/ieee80211_i.h	2008-02-15 22:21:37.000000000 +0100
 | 
			
		||||
@@ -26,6 +26,16 @@
 | 
			
		||||
 #include "ieee80211_key.h"
 | 
			
		||||
 #include "sta_info.h"
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+#define BIT(nr)		(1 << (nr))
 | 
			
		||||
+
 | 
			
		||||
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
 | 
			
		||||
+extern char *print_mac(char *buf, const u8 *addr);
 | 
			
		||||
+#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
 | 
			
		||||
+
 | 
			
		||||
+#define CONFIG_MAC80211_RC_DEFAULT	__stringify(__CONFIG_MAC80211_RC_DEFAULT)
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
 /* ieee80211.o internal definitions, etc. These are not included into
 | 
			
		||||
  * low-level drivers. */
 | 
			
		||||
 
 | 
			
		||||
Index: mac80211/net/mac80211/ieee80211_ioctl.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/ieee80211_ioctl.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/ieee80211_ioctl.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -207,7 +207,7 @@ static int ieee80211_ioctl_giwrange(stru
 | 
			
		||||
 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
 | 
			
		||||
 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 | 
			
		||||
 
 | 
			
		||||
-	range->scan_capa |= IW_SCAN_CAPA_ESSID;
 | 
			
		||||
+//	range->scan_capa |= IW_SCAN_CAPA_ESSID;
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
Index: mac80211/net/wireless/core.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/wireless/core.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/wireless/core.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_inf
 | 
			
		||||
 
 | 
			
		||||
 	if (info->attrs[NL80211_ATTR_IFINDEX]) {
 | 
			
		||||
 		ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
 | 
			
		||||
-		dev = dev_get_by_index(&init_net, ifindex);
 | 
			
		||||
+		dev = dev_get_by_index(ifindex);
 | 
			
		||||
 		if (dev) {
 | 
			
		||||
 			if (dev->ieee80211_ptr)
 | 
			
		||||
 				byifidx =
 | 
			
		||||
@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifinde
 | 
			
		||||
 	struct net_device *dev;
 | 
			
		||||
 
 | 
			
		||||
 	mutex_lock(&cfg80211_drv_mutex);
 | 
			
		||||
-	dev = dev_get_by_index(&init_net, ifindex);
 | 
			
		||||
+	dev = dev_get_by_index(ifindex);
 | 
			
		||||
 	if (!dev)
 | 
			
		||||
 		goto out;
 | 
			
		||||
 	if (dev->ieee80211_ptr) {
 | 
			
		||||
Index: mac80211/net/wireless/nl80211.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/wireless/nl80211.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/wireless/nl80211.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(s
 | 
			
		||||
 		return -EINVAL;
 | 
			
		||||
 
 | 
			
		||||
 	ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
 | 
			
		||||
-	*dev = dev_get_by_index(&init_net, ifindex);
 | 
			
		||||
+	*dev = dev_get_by_index(ifindex);
 | 
			
		||||
 	if (!*dev)
 | 
			
		||||
 		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
@@ -959,7 +959,7 @@ static int get_vlan(struct nlattr *vlana
 | 
			
		||||
 	*vlan = NULL;
 | 
			
		||||
 
 | 
			
		||||
 	if (vlanattr) {
 | 
			
		||||
-		*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
 | 
			
		||||
+		*vlan = dev_get_by_index(nla_get_u32(vlanattr));
 | 
			
		||||
 		if (!*vlan)
 | 
			
		||||
 			return -ENODEV;
 | 
			
		||||
 		if (!(*vlan)->ieee80211_ptr)
 | 
			
		||||
Index: mac80211/net/mac80211/cfg.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/cfg.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/cfg.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
 #include <linux/ieee80211.h>
 | 
			
		||||
 #include <linux/nl80211.h>
 | 
			
		||||
 #include <linux/rtnetlink.h>
 | 
			
		||||
-#include <net/net_namespace.h>
 | 
			
		||||
 #include <linux/rcupdate.h>
 | 
			
		||||
 #include <net/cfg80211.h>
 | 
			
		||||
 #include "ieee80211_i.h"
 | 
			
		||||
@@ -68,7 +67,7 @@ static int ieee80211_del_iface(struct wi
 | 
			
		||||
 		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
 	/* we're under RTNL */
 | 
			
		||||
-	dev = __dev_get_by_index(&init_net, ifindex);
 | 
			
		||||
+	dev = __dev_get_by_index(ifindex);
 | 
			
		||||
 	if (!dev)
 | 
			
		||||
 		return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +88,7 @@ static int ieee80211_change_iface(struct
 | 
			
		||||
 		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
 	/* we're under RTNL */
 | 
			
		||||
-	dev = __dev_get_by_index(&init_net, ifindex);
 | 
			
		||||
+	dev = __dev_get_by_index(ifindex);
 | 
			
		||||
 	if (!dev)
 | 
			
		||||
 		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
Index: mac80211/net/mac80211/tx.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/tx.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/tx.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
 #include <linux/etherdevice.h>
 | 
			
		||||
 #include <linux/bitmap.h>
 | 
			
		||||
 #include <linux/rcupdate.h>
 | 
			
		||||
-#include <net/net_namespace.h>
 | 
			
		||||
 #include <net/ieee80211_radiotap.h>
 | 
			
		||||
 #include <net/cfg80211.h>
 | 
			
		||||
 #include <net/mac80211.h>
 | 
			
		||||
@@ -1051,7 +1050,7 @@ static int ieee80211_tx_prepare(struct i
 | 
			
		||||
 	struct net_device *dev;
 | 
			
		||||
 
 | 
			
		||||
 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
 | 
			
		||||
-	dev = dev_get_by_index(&init_net, pkt_data->ifindex);
 | 
			
		||||
+	dev = dev_get_by_index(pkt_data->ifindex);
 | 
			
		||||
 	if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
 | 
			
		||||
 		dev_put(dev);
 | 
			
		||||
 		dev = NULL;
 | 
			
		||||
@@ -1265,7 +1264,7 @@ int ieee80211_master_start_xmit(struct s
 | 
			
		||||
 	memset(&control, 0, sizeof(struct ieee80211_tx_control));
 | 
			
		||||
 
 | 
			
		||||
 	if (pkt_data->ifindex)
 | 
			
		||||
-		odev = dev_get_by_index(&init_net, pkt_data->ifindex);
 | 
			
		||||
+		odev = dev_get_by_index(pkt_data->ifindex);
 | 
			
		||||
 	if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
 | 
			
		||||
 		dev_put(odev);
 | 
			
		||||
 		odev = NULL;
 | 
			
		||||
Index: mac80211/net/mac80211/util.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/mac80211/util.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/mac80211/util.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -20,7 +20,6 @@
 | 
			
		||||
 #include <linux/if_arp.h>
 | 
			
		||||
 #include <linux/wireless.h>
 | 
			
		||||
 #include <linux/bitmap.h>
 | 
			
		||||
-#include <net/net_namespace.h>
 | 
			
		||||
 #include <net/cfg80211.h>
 | 
			
		||||
 #include <net/rtnetlink.h>
 | 
			
		||||
 
 | 
			
		||||
Index: mac80211/net/wireless/sysfs.c
 | 
			
		||||
===================================================================
 | 
			
		||||
--- mac80211.orig/net/wireless/sysfs.c	2008-02-15 22:20:53.000000000 +0100
 | 
			
		||||
+++ mac80211/net/wireless/sysfs.c	2008-02-15 22:21:01.000000000 +0100
 | 
			
		||||
@@ -53,7 +53,8 @@ static void wiphy_dev_release(struct dev
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 #ifdef CONFIG_HOTPLUG
 | 
			
		||||
-static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 | 
			
		||||
+static int wiphy_uevent(struct device *dev, char **envp, int num_envp,
 | 
			
		||||
+			char *buffer, int buffer_size)
 | 
			
		||||
 {
 | 
			
		||||
 	/* TODO, we probably need stuff here */
 | 
			
		||||
 	return 0;
 | 
			
		||||
@ -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 */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										307
									
								
								package/mac80211/src/include/net/wireless.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								package/mac80211/src/include/net/wireless.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,307 @@
 | 
			
		||||
#ifndef __NET_WIRELESS_H
 | 
			
		||||
#define __NET_WIRELESS_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 802.11 device management
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
#include <linux/debugfs.h>
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
#include <net/cfg80211.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum ieee80211_band - supported frequency bands
 | 
			
		||||
 *
 | 
			
		||||
 * The bands are assigned this way because the supported
 | 
			
		||||
 * bitrates differ in these bands.
 | 
			
		||||
 *
 | 
			
		||||
 * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
 | 
			
		||||
 * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_band {
 | 
			
		||||
	IEEE80211_BAND_2GHZ,
 | 
			
		||||
	IEEE80211_BAND_5GHZ,
 | 
			
		||||
 | 
			
		||||
	/* keep last */
 | 
			
		||||
	IEEE80211_NUM_BANDS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum ieee80211_channel_flags - channel flags
 | 
			
		||||
 *
 | 
			
		||||
 * Channel flags set by the regulatory control code.
 | 
			
		||||
 *
 | 
			
		||||
 * @IEEE80211_CHAN_DISABLED: This channel is disabled.
 | 
			
		||||
 * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
 | 
			
		||||
 *	on this channel.
 | 
			
		||||
 * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
 | 
			
		||||
 * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_channel_flags {
 | 
			
		||||
	IEEE80211_CHAN_DISABLED		= 1<<0,
 | 
			
		||||
	IEEE80211_CHAN_PASSIVE_SCAN	= 1<<1,
 | 
			
		||||
	IEEE80211_CHAN_NO_IBSS		= 1<<2,
 | 
			
		||||
	IEEE80211_CHAN_RADAR		= 1<<3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ieee80211_channel - channel definition
 | 
			
		||||
 *
 | 
			
		||||
 * This structure describes a single channel for use
 | 
			
		||||
 * with cfg80211.
 | 
			
		||||
 *
 | 
			
		||||
 * @center_freq: center frequency in MHz
 | 
			
		||||
 * @hw_value: hardware-specific value for the channel
 | 
			
		||||
 * @flags: channel flags from &enum ieee80211_channel_flags.
 | 
			
		||||
 * @orig_flags: channel flags at registration time, used by regulatory
 | 
			
		||||
 *	code to support devices with additional restrictions
 | 
			
		||||
 * @band: band this channel belongs to.
 | 
			
		||||
 * @max_antenna_gain: maximum antenna gain in dBi
 | 
			
		||||
 * @max_power: maximum transmission power (in dBm)
 | 
			
		||||
 * @orig_mag: internal use
 | 
			
		||||
 * @orig_mpwr: internal use
 | 
			
		||||
 */
 | 
			
		||||
struct ieee80211_channel {
 | 
			
		||||
	enum ieee80211_band band;
 | 
			
		||||
	u16 center_freq;
 | 
			
		||||
	u16 hw_value;
 | 
			
		||||
	u32 flags;
 | 
			
		||||
	int max_antenna_gain;
 | 
			
		||||
	int max_power;
 | 
			
		||||
	u32 orig_flags;
 | 
			
		||||
	int orig_mag, orig_mpwr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum ieee80211_rate_flags - rate flags
 | 
			
		||||
 *
 | 
			
		||||
 * Hardware/specification flags for rates. These are structured
 | 
			
		||||
 * in a way that allows using the same bitrate structure for
 | 
			
		||||
 * different bands/PHY modes.
 | 
			
		||||
 *
 | 
			
		||||
 * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short
 | 
			
		||||
 *	preamble on this bitrate; only relevant in 2.4GHz band and
 | 
			
		||||
 *	with CCK rates.
 | 
			
		||||
 * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate
 | 
			
		||||
 *	when used with 802.11a (on the 5 GHz band); filled by the
 | 
			
		||||
 *	core code when registering the wiphy.
 | 
			
		||||
 * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate
 | 
			
		||||
 *	when used with 802.11b (on the 2.4 GHz band); filled by the
 | 
			
		||||
 *	core code when registering the wiphy.
 | 
			
		||||
 * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate
 | 
			
		||||
 *	when used with 802.11g (on the 2.4 GHz band); filled by the
 | 
			
		||||
 *	core code when registering the wiphy.
 | 
			
		||||
 * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode.
 | 
			
		||||
 */
 | 
			
		||||
enum ieee80211_rate_flags {
 | 
			
		||||
	IEEE80211_RATE_SHORT_PREAMBLE	= 1<<0,
 | 
			
		||||
	IEEE80211_RATE_MANDATORY_A	= 1<<1,
 | 
			
		||||
	IEEE80211_RATE_MANDATORY_B	= 1<<2,
 | 
			
		||||
	IEEE80211_RATE_MANDATORY_G	= 1<<3,
 | 
			
		||||
	IEEE80211_RATE_ERP_G		= 1<<4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ieee80211_rate - bitrate definition
 | 
			
		||||
 *
 | 
			
		||||
 * This structure describes a bitrate that an 802.11 PHY can
 | 
			
		||||
 * operate with. The two values @hw_value and @hw_value_short
 | 
			
		||||
 * are only for driver use when pointers to this structure are
 | 
			
		||||
 * passed around.
 | 
			
		||||
 *
 | 
			
		||||
 * @flags: rate-specific flags
 | 
			
		||||
 * @bitrate: bitrate in units of 100 Kbps
 | 
			
		||||
 * @hw_value: driver/hardware value for this rate
 | 
			
		||||
 * @hw_value_short: driver/hardware value for this rate when
 | 
			
		||||
 *	short preamble is used
 | 
			
		||||
 */
 | 
			
		||||
struct ieee80211_rate {
 | 
			
		||||
	u32 flags;
 | 
			
		||||
	u16 bitrate;
 | 
			
		||||
	u16 hw_value, hw_value_short;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ieee80211_ht_info - describing STA's HT capabilities
 | 
			
		||||
 *
 | 
			
		||||
 * This structure describes most essential parameters needed
 | 
			
		||||
 * to describe 802.11n HT capabilities for an STA.
 | 
			
		||||
 *
 | 
			
		||||
 * @ht_supported: is HT supported by STA, 0: no, 1: yes
 | 
			
		||||
 * @cap: HT capabilities map as described in 802.11n spec
 | 
			
		||||
 * @ampdu_factor: Maximum A-MPDU length factor
 | 
			
		||||
 * @ampdu_density: Minimum A-MPDU spacing
 | 
			
		||||
 * @supp_mcs_set: Supported MCS set as described in 802.11n spec
 | 
			
		||||
 */
 | 
			
		||||
struct ieee80211_ht_info {
 | 
			
		||||
	u16 cap; /* use IEEE80211_HT_CAP_ */
 | 
			
		||||
	u8 ht_supported;
 | 
			
		||||
	u8 ampdu_factor;
 | 
			
		||||
	u8 ampdu_density;
 | 
			
		||||
	u8 supp_mcs_set[16];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ieee80211_supported_band - frequency band definition
 | 
			
		||||
 *
 | 
			
		||||
 * This structure describes a frequency band a wiphy
 | 
			
		||||
 * is able to operate in.
 | 
			
		||||
 *
 | 
			
		||||
 * @channels: Array of channels the hardware can operate in
 | 
			
		||||
 *	in this band.
 | 
			
		||||
 * @band: the band this structure represents
 | 
			
		||||
 * @n_channels: Number of channels in @channels
 | 
			
		||||
 * @bitrates: Array of bitrates the hardware can operate with
 | 
			
		||||
 *	in this band. Must be sorted to give a valid "supported
 | 
			
		||||
 *	rates" IE, i.e. CCK rates first, then OFDM.
 | 
			
		||||
 * @n_bitrates: Number of bitrates in @bitrates
 | 
			
		||||
 */
 | 
			
		||||
struct ieee80211_supported_band {
 | 
			
		||||
	struct ieee80211_channel *channels;
 | 
			
		||||
	struct ieee80211_rate *bitrates;
 | 
			
		||||
	enum ieee80211_band band;
 | 
			
		||||
	int n_channels;
 | 
			
		||||
	int n_bitrates;
 | 
			
		||||
	struct ieee80211_ht_info ht_info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct wiphy - wireless hardware description
 | 
			
		||||
 * @idx: the wiphy index assigned to this item
 | 
			
		||||
 * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
 | 
			
		||||
 */
 | 
			
		||||
struct wiphy {
 | 
			
		||||
	/* assign these fields before you register the wiphy */
 | 
			
		||||
 | 
			
		||||
	/* permanent MAC address */
 | 
			
		||||
	u8 perm_addr[ETH_ALEN];
 | 
			
		||||
 | 
			
		||||
	/* If multiple wiphys are registered and you're handed e.g.
 | 
			
		||||
	 * a regular netdev with assigned ieee80211_ptr, you won't
 | 
			
		||||
	 * know whether it points to a wiphy your driver has registered
 | 
			
		||||
	 * or not. Assign this to something global to your driver to
 | 
			
		||||
	 * help determine whether you own this wiphy or not. */
 | 
			
		||||
	void *privid;
 | 
			
		||||
 | 
			
		||||
	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
 | 
			
		||||
 | 
			
		||||
	/* fields below are read-only, assigned by cfg80211 */
 | 
			
		||||
 | 
			
		||||
	/* the item in /sys/class/ieee80211/ points to this,
 | 
			
		||||
	 * you need use set_wiphy_dev() (see below) */
 | 
			
		||||
	struct device dev;
 | 
			
		||||
 | 
			
		||||
	/* dir in debugfs: ieee80211/<wiphyname> */
 | 
			
		||||
	struct dentry *debugfsdir;
 | 
			
		||||
 | 
			
		||||
	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** struct wireless_dev - wireless per-netdev state
 | 
			
		||||
 *
 | 
			
		||||
 * This structure must be allocated by the driver/stack
 | 
			
		||||
 * that uses the ieee80211_ptr field in struct net_device
 | 
			
		||||
 * (this is intentional so it can be allocated along with
 | 
			
		||||
 * the netdev.)
 | 
			
		||||
 *
 | 
			
		||||
 * @wiphy: pointer to hardware description
 | 
			
		||||
 */
 | 
			
		||||
struct wireless_dev {
 | 
			
		||||
	struct wiphy *wiphy;
 | 
			
		||||
 | 
			
		||||
	/* private to the generic wireless code */
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	struct net_device *netdev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_priv - return priv from wiphy
 | 
			
		||||
 */
 | 
			
		||||
static inline void *wiphy_priv(struct wiphy *wiphy)
 | 
			
		||||
{
 | 
			
		||||
	BUG_ON(!wiphy);
 | 
			
		||||
	return &wiphy->priv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * set_wiphy_dev - set device pointer for wiphy
 | 
			
		||||
 */
 | 
			
		||||
static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	wiphy->dev.parent = dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_dev - get wiphy dev pointer
 | 
			
		||||
 */
 | 
			
		||||
static inline struct device *wiphy_dev(struct wiphy *wiphy)
 | 
			
		||||
{
 | 
			
		||||
	return wiphy->dev.parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_name - get wiphy name
 | 
			
		||||
 */
 | 
			
		||||
static inline char *wiphy_name(struct wiphy *wiphy)
 | 
			
		||||
{
 | 
			
		||||
	return wiphy->dev.bus_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wdev_priv - return wiphy priv from wireless_dev
 | 
			
		||||
 */
 | 
			
		||||
static inline void *wdev_priv(struct wireless_dev *wdev)
 | 
			
		||||
{
 | 
			
		||||
	BUG_ON(!wdev);
 | 
			
		||||
	return wiphy_priv(wdev->wiphy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_new - create a new wiphy for use with cfg80211
 | 
			
		||||
 *
 | 
			
		||||
 * create a new wiphy and associate the given operations with it.
 | 
			
		||||
 * @sizeof_priv bytes are allocated for private use.
 | 
			
		||||
 *
 | 
			
		||||
 * the returned pointer must be assigned to each netdev's
 | 
			
		||||
 * ieee80211_ptr for proper operation.
 | 
			
		||||
 */
 | 
			
		||||
struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_register - register a wiphy with cfg80211
 | 
			
		||||
 *
 | 
			
		||||
 * register the given wiphy
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a non-negative wiphy index or a negative error code.
 | 
			
		||||
 */
 | 
			
		||||
extern int wiphy_register(struct wiphy *wiphy);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_unregister - deregister a wiphy from cfg80211
 | 
			
		||||
 *
 | 
			
		||||
 * unregister a device with the given priv pointer.
 | 
			
		||||
 * After this call, no more requests can be made with this priv
 | 
			
		||||
 * pointer, but the call may sleep to wait for an outstanding
 | 
			
		||||
 * request that is being handled.
 | 
			
		||||
 */
 | 
			
		||||
extern void wiphy_unregister(struct wiphy *wiphy);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wiphy_free - free wiphy
 | 
			
		||||
 */
 | 
			
		||||
extern void wiphy_free(struct wiphy *wiphy);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ieee80211_channel_to_frequency - convert channel number to frequency
 | 
			
		||||
 */
 | 
			
		||||
extern int ieee80211_channel_to_frequency(int chan);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ieee80211_frequency_to_channel - convert frequency to channel number
 | 
			
		||||
 */
 | 
			
		||||
extern int ieee80211_frequency_to_channel(int freq);
 | 
			
		||||
 | 
			
		||||
#endif /* __NET_WIRELESS_H */
 | 
			
		||||
@ -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 */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										285
									
								
								package/mac80211/src/net/mac80211/rc80211_pid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								package/mac80211/src/net/mac80211/rc80211_pid.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,285 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
 | 
			
		||||
 * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef RC80211_PID_H
 | 
			
		||||
#define RC80211_PID_H
 | 
			
		||||
 | 
			
		||||
/* Sampling period for measuring percentage of failed frames in ms. */
 | 
			
		||||
#define RC_PID_INTERVAL			125
 | 
			
		||||
 | 
			
		||||
/* Exponential averaging smoothness (used for I part of PID controller) */
 | 
			
		||||
#define RC_PID_SMOOTHING_SHIFT		3
 | 
			
		||||
#define RC_PID_SMOOTHING		(1 << RC_PID_SMOOTHING_SHIFT)
 | 
			
		||||
 | 
			
		||||
/* Sharpening factor (used for D part of PID controller) */
 | 
			
		||||
#define RC_PID_SHARPENING_FACTOR	0
 | 
			
		||||
#define RC_PID_SHARPENING_DURATION	0
 | 
			
		||||
 | 
			
		||||
/* Fixed point arithmetic shifting amount. */
 | 
			
		||||
#define RC_PID_ARITH_SHIFT		8
 | 
			
		||||
 | 
			
		||||
/* Fixed point arithmetic factor. */
 | 
			
		||||
#define RC_PID_ARITH_FACTOR		(1 << RC_PID_ARITH_SHIFT)
 | 
			
		||||
 | 
			
		||||
/* Proportional PID component coefficient. */
 | 
			
		||||
#define RC_PID_COEFF_P			15
 | 
			
		||||
/* Integral PID component coefficient. */
 | 
			
		||||
#define RC_PID_COEFF_I			9
 | 
			
		||||
/* Derivative PID component coefficient. */
 | 
			
		||||
#define RC_PID_COEFF_D			15
 | 
			
		||||
 | 
			
		||||
/* Target failed frames rate for the PID controller. NB: This effectively gives
 | 
			
		||||
 * maximum failed frames percentage we're willing to accept. If the wireless
 | 
			
		||||
 * link quality is good, the controller will fail to adjust failed frames
 | 
			
		||||
 * percentage to the target. This is intentional.
 | 
			
		||||
 */
 | 
			
		||||
#define RC_PID_TARGET_PF		14
 | 
			
		||||
 | 
			
		||||
/* Rate behaviour normalization quantity over time. */
 | 
			
		||||
#define RC_PID_NORM_OFFSET		3
 | 
			
		||||
 | 
			
		||||
/* Push high rates right after loading. */
 | 
			
		||||
#define RC_PID_FAST_START		0
 | 
			
		||||
 | 
			
		||||
/* Arithmetic right shift for positive and negative values for ISO C. */
 | 
			
		||||
#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
 | 
			
		||||
	(x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
 | 
			
		||||
 | 
			
		||||
enum rc_pid_event_type {
 | 
			
		||||
	RC_PID_EVENT_TYPE_TX_STATUS,
 | 
			
		||||
	RC_PID_EVENT_TYPE_RATE_CHANGE,
 | 
			
		||||
	RC_PID_EVENT_TYPE_TX_RATE,
 | 
			
		||||
	RC_PID_EVENT_TYPE_PF_SAMPLE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union rc_pid_event_data {
 | 
			
		||||
	/* RC_PID_EVENT_TX_STATUS */
 | 
			
		||||
	struct {
 | 
			
		||||
		struct ieee80211_tx_status tx_status;
 | 
			
		||||
	};
 | 
			
		||||
	/* RC_PID_EVENT_TYPE_RATE_CHANGE */
 | 
			
		||||
	/* RC_PID_EVENT_TYPE_TX_RATE */
 | 
			
		||||
	struct {
 | 
			
		||||
		int index;
 | 
			
		||||
		int rate;
 | 
			
		||||
	};
 | 
			
		||||
	/* RC_PID_EVENT_TYPE_PF_SAMPLE */
 | 
			
		||||
	struct {
 | 
			
		||||
		s32 pf_sample;
 | 
			
		||||
		s32 prop_err;
 | 
			
		||||
		s32 int_err;
 | 
			
		||||
		s32 der_err;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rc_pid_event {
 | 
			
		||||
	/* The time when the event occured */
 | 
			
		||||
	unsigned long timestamp;
 | 
			
		||||
 | 
			
		||||
	/* Event ID number */
 | 
			
		||||
	unsigned int id;
 | 
			
		||||
 | 
			
		||||
	/* Type of event */
 | 
			
		||||
	enum rc_pid_event_type type;
 | 
			
		||||
 | 
			
		||||
	/* type specific data */
 | 
			
		||||
	union rc_pid_event_data data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Size of the event ring buffer. */
 | 
			
		||||
#define RC_PID_EVENT_RING_SIZE 32
 | 
			
		||||
 | 
			
		||||
struct rc_pid_event_buffer {
 | 
			
		||||
	/* Counter that generates event IDs */
 | 
			
		||||
	unsigned int ev_count;
 | 
			
		||||
 | 
			
		||||
	/* Ring buffer of events */
 | 
			
		||||
	struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE];
 | 
			
		||||
 | 
			
		||||
	/* Index to the entry in events_buf to be reused */
 | 
			
		||||
	unsigned int next_entry;
 | 
			
		||||
 | 
			
		||||
	/* Lock that guards against concurrent access to this buffer struct */
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
 | 
			
		||||
	/* Wait queue for poll/select and blocking I/O */
 | 
			
		||||
	wait_queue_head_t waitqueue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rc_pid_events_file_info {
 | 
			
		||||
	/* The event buffer we read */
 | 
			
		||||
	struct rc_pid_event_buffer *events;
 | 
			
		||||
 | 
			
		||||
	/* The entry we have should read next */
 | 
			
		||||
	unsigned int next_entry;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rc_pid_debugfs_entries - tunable parameters
 | 
			
		||||
 *
 | 
			
		||||
 * Algorithm parameters, tunable via debugfs.
 | 
			
		||||
 * @dir: the debugfs directory for a specific phy
 | 
			
		||||
 * @target: target percentage for failed frames
 | 
			
		||||
 * @sampling_period: error sampling interval in milliseconds
 | 
			
		||||
 * @coeff_p: absolute value of the proportional coefficient
 | 
			
		||||
 * @coeff_i: absolute value of the integral coefficient
 | 
			
		||||
 * @coeff_d: absolute value of the derivative coefficient
 | 
			
		||||
 * @smoothing_shift: absolute value of the integral smoothing factor (i.e.
 | 
			
		||||
 *	amount of smoothing introduced by the exponential moving average)
 | 
			
		||||
 * @sharpen_factor: absolute value of the derivative sharpening factor (i.e.
 | 
			
		||||
 *	amount of emphasis given to the derivative term after low activity
 | 
			
		||||
 *	events)
 | 
			
		||||
 * @sharpen_duration: duration of the sharpening effect after the detected low
 | 
			
		||||
 *	activity event, relative to sampling_period
 | 
			
		||||
 * @norm_offset: amount of normalization periodically performed on the learnt
 | 
			
		||||
 *	rate behaviour values (lower means we should trust more what we learnt
 | 
			
		||||
 *	about behaviour of rates, higher means we should trust more the natural
 | 
			
		||||
 *	ordering of rates)
 | 
			
		||||
 * @fast_start: if Y, push high rates right after initialization
 | 
			
		||||
 */
 | 
			
		||||
struct rc_pid_debugfs_entries {
 | 
			
		||||
	struct dentry *dir;
 | 
			
		||||
	struct dentry *target;
 | 
			
		||||
	struct dentry *sampling_period;
 | 
			
		||||
	struct dentry *coeff_p;
 | 
			
		||||
	struct dentry *coeff_i;
 | 
			
		||||
	struct dentry *coeff_d;
 | 
			
		||||
	struct dentry *smoothing_shift;
 | 
			
		||||
	struct dentry *sharpen_factor;
 | 
			
		||||
	struct dentry *sharpen_duration;
 | 
			
		||||
	struct dentry *norm_offset;
 | 
			
		||||
	struct dentry *fast_start;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					     struct ieee80211_tx_status *stat);
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					       int index, int rate);
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					   int index, int rate);
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					     s32 pf_sample, s32 prop_err,
 | 
			
		||||
					     s32 int_err, s32 der_err);
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
 | 
			
		||||
					     struct dentry *dir);
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta);
 | 
			
		||||
 | 
			
		||||
struct rc_pid_sta_info {
 | 
			
		||||
	unsigned long last_change;
 | 
			
		||||
	unsigned long last_sample;
 | 
			
		||||
 | 
			
		||||
	u32 tx_num_failed;
 | 
			
		||||
	u32 tx_num_xmit;
 | 
			
		||||
 | 
			
		||||
	/* Average failed frames percentage error (i.e. actual vs. target
 | 
			
		||||
	 * percentage), scaled by RC_PID_SMOOTHING. This value is computed
 | 
			
		||||
	 * using using an exponential weighted average technique:
 | 
			
		||||
	 *
 | 
			
		||||
	 *           (RC_PID_SMOOTHING - 1) * err_avg_old + err
 | 
			
		||||
	 * err_avg = ------------------------------------------
 | 
			
		||||
	 *                       RC_PID_SMOOTHING
 | 
			
		||||
	 *
 | 
			
		||||
	 * where err_avg is the new approximation, err_avg_old the previous one
 | 
			
		||||
	 * and err is the error w.r.t. to the current failed frames percentage
 | 
			
		||||
	 * sample. Note that the bigger RC_PID_SMOOTHING the more weight is
 | 
			
		||||
	 * given to the previous estimate, resulting in smoother behavior (i.e.
 | 
			
		||||
	 * corresponding to a longer integration window).
 | 
			
		||||
	 *
 | 
			
		||||
	 * For computation, we actually don't use the above formula, but this
 | 
			
		||||
	 * one:
 | 
			
		||||
	 *
 | 
			
		||||
	 * err_avg_scaled = err_avg_old_scaled - err_avg_old + err
 | 
			
		||||
	 *
 | 
			
		||||
	 * where:
 | 
			
		||||
	 * 	err_avg_scaled = err * RC_PID_SMOOTHING
 | 
			
		||||
	 * 	err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
 | 
			
		||||
	 *
 | 
			
		||||
	 * This avoids floating point numbers and the per_failed_old value can
 | 
			
		||||
	 * easily be obtained by shifting per_failed_old_scaled right by
 | 
			
		||||
	 * RC_PID_SMOOTHING_SHIFT.
 | 
			
		||||
	 */
 | 
			
		||||
	s32 err_avg_sc;
 | 
			
		||||
 | 
			
		||||
	/* Last framed failes percentage sample. */
 | 
			
		||||
	u32 last_pf;
 | 
			
		||||
 | 
			
		||||
	/* Sharpening needed. */
 | 
			
		||||
	u8 sharp_cnt;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	/* Event buffer */
 | 
			
		||||
	struct rc_pid_event_buffer events;
 | 
			
		||||
 | 
			
		||||
	/* Events debugfs file entry */
 | 
			
		||||
	struct dentry *events_entry;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
 | 
			
		||||
 * be tuned individually for each interface.
 | 
			
		||||
 */
 | 
			
		||||
struct rc_pid_rateinfo {
 | 
			
		||||
 | 
			
		||||
	/* Map sorted rates to rates in ieee80211_hw_mode. */
 | 
			
		||||
	int index;
 | 
			
		||||
 | 
			
		||||
	/* Map rates in ieee80211_hw_mode to sorted rates. */
 | 
			
		||||
	int rev_index;
 | 
			
		||||
 | 
			
		||||
	/* Did we do any measurement on this rate? */
 | 
			
		||||
	bool valid;
 | 
			
		||||
 | 
			
		||||
	/* Comparison with the lowest rate. */
 | 
			
		||||
	int diff;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rc_pid_info {
 | 
			
		||||
 | 
			
		||||
	/* The failed frames percentage target. */
 | 
			
		||||
	unsigned int target;
 | 
			
		||||
 | 
			
		||||
	/* Rate at which failed frames percentage is sampled in 0.001s. */
 | 
			
		||||
	unsigned int sampling_period;
 | 
			
		||||
 | 
			
		||||
	/* P, I and D coefficients. */
 | 
			
		||||
	int coeff_p;
 | 
			
		||||
	int coeff_i;
 | 
			
		||||
	int coeff_d;
 | 
			
		||||
 | 
			
		||||
	/* Exponential averaging shift. */
 | 
			
		||||
	unsigned int smoothing_shift;
 | 
			
		||||
 | 
			
		||||
	/* Sharpening factor and duration. */
 | 
			
		||||
	unsigned int sharpen_factor;
 | 
			
		||||
	unsigned int sharpen_duration;
 | 
			
		||||
 | 
			
		||||
	/* Normalization offset. */
 | 
			
		||||
	unsigned int norm_offset;
 | 
			
		||||
 | 
			
		||||
	/* Fast starst parameter. */
 | 
			
		||||
	unsigned int fast_start;
 | 
			
		||||
 | 
			
		||||
	/* Rates information. */
 | 
			
		||||
	struct rc_pid_rateinfo *rinfo;
 | 
			
		||||
 | 
			
		||||
	/* Index of the last used rate. */
 | 
			
		||||
	int oldrate;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	/* Debugfs entries created for the parameters above. */
 | 
			
		||||
	struct rc_pid_debugfs_entries dentries;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* RC80211_PID_H */
 | 
			
		||||
							
								
								
									
										550
									
								
								package/mac80211/src/net/mac80211/rc80211_pid_algo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										550
									
								
								package/mac80211/src/net/mac80211/rc80211_pid_algo.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,550 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2002-2005, Instant802 Networks, Inc.
 | 
			
		||||
 * Copyright 2005, Devicescape Software, Inc.
 | 
			
		||||
 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
 | 
			
		||||
 * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/debugfs.h>
 | 
			
		||||
#include <net/mac80211.h>
 | 
			
		||||
#include "ieee80211_rate.h"
 | 
			
		||||
 | 
			
		||||
#include "rc80211_pid.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* This is an implementation of a TX rate control algorithm that uses a PID
 | 
			
		||||
 * controller. Given a target failed frames rate, the controller decides about
 | 
			
		||||
 * TX rate changes to meet the target failed frames rate.
 | 
			
		||||
 *
 | 
			
		||||
 * The controller basically computes the following:
 | 
			
		||||
 *
 | 
			
		||||
 * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening)
 | 
			
		||||
 *
 | 
			
		||||
 * where
 | 
			
		||||
 * 	adj	adjustment value that is used to switch TX rate (see below)
 | 
			
		||||
 * 	err	current error: target vs. current failed frames percentage
 | 
			
		||||
 * 	last_err	last error
 | 
			
		||||
 * 	err_avg	average (i.e. poor man's integral) of recent errors
 | 
			
		||||
 *	sharpening	non-zero when fast response is needed (i.e. right after
 | 
			
		||||
 *			association or no frames sent for a long time), heading
 | 
			
		||||
 * 			to zero over time
 | 
			
		||||
 * 	CP	Proportional coefficient
 | 
			
		||||
 * 	CI	Integral coefficient
 | 
			
		||||
 * 	CD	Derivative coefficient
 | 
			
		||||
 *
 | 
			
		||||
 * CP, CI, CD are subject to careful tuning.
 | 
			
		||||
 *
 | 
			
		||||
 * The integral component uses a exponential moving average approach instead of
 | 
			
		||||
 * an actual sliding window. The advantage is that we don't need to keep an
 | 
			
		||||
 * array of the last N error values and computation is easier.
 | 
			
		||||
 *
 | 
			
		||||
 * Once we have the adj value, we map it to a rate by means of a learning
 | 
			
		||||
 * algorithm. This algorithm keeps the state of the percentual failed frames
 | 
			
		||||
 * difference between rates. The behaviour of the lowest available rate is kept
 | 
			
		||||
 * as a reference value, and every time we switch between two rates, we compute
 | 
			
		||||
 * the difference between the failed frames each rate exhibited. By doing so,
 | 
			
		||||
 * we compare behaviours which different rates exhibited in adjacent timeslices,
 | 
			
		||||
 * thus the comparison is minimally affected by external conditions. This
 | 
			
		||||
 * difference gets propagated to the whole set of measurements, so that the
 | 
			
		||||
 * reference is always the same. Periodically, we normalize this set so that
 | 
			
		||||
 * recent events weigh the most. By comparing the adj value with this set, we
 | 
			
		||||
 * avoid pejorative switches to lower rates and allow for switches to higher
 | 
			
		||||
 * rates if they behaved well.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that for the computations we use a fixed-point representation to avoid
 | 
			
		||||
 * floating point arithmetic. Hence, all values are shifted left by
 | 
			
		||||
 * RC_PID_ARITH_SHIFT.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Adjust the rate while ensuring that we won't switch to a lower rate if it
 | 
			
		||||
 * exhibited a worse failed frames behaviour and we'll choose the highest rate
 | 
			
		||||
 * whose failed frames behaviour is not worse than the one of the original rate
 | 
			
		||||
 * target. While at it, check that the new rate is valid. */
 | 
			
		||||
static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
 | 
			
		||||
					 struct sta_info *sta, int adj,
 | 
			
		||||
					 struct rc_pid_rateinfo *rinfo)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
	int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
 | 
			
		||||
	int cur = sta->txrate_idx;
 | 
			
		||||
 | 
			
		||||
	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
	band = sband->band;
 | 
			
		||||
	n_bitrates = sband->n_bitrates;
 | 
			
		||||
 | 
			
		||||
	/* Map passed arguments to sorted values. */
 | 
			
		||||
	cur_sorted = rinfo[cur].rev_index;
 | 
			
		||||
	new_sorted = cur_sorted + adj;
 | 
			
		||||
 | 
			
		||||
	/* Check limits. */
 | 
			
		||||
	if (new_sorted < 0)
 | 
			
		||||
		new_sorted = rinfo[0].rev_index;
 | 
			
		||||
	else if (new_sorted >= n_bitrates)
 | 
			
		||||
		new_sorted = rinfo[n_bitrates - 1].rev_index;
 | 
			
		||||
 | 
			
		||||
	tmp = new_sorted;
 | 
			
		||||
 | 
			
		||||
	if (adj < 0) {
 | 
			
		||||
		/* Ensure that the rate decrease isn't disadvantageous. */
 | 
			
		||||
		for (probe = cur_sorted; probe >= new_sorted; probe--)
 | 
			
		||||
			if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
 | 
			
		||||
			    rate_supported(sta, band, rinfo[probe].index))
 | 
			
		||||
				tmp = probe;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Look for rate increase with zero (or below) cost. */
 | 
			
		||||
		for (probe = new_sorted + 1; probe < n_bitrates; probe++)
 | 
			
		||||
			if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
 | 
			
		||||
			    rate_supported(sta, band, rinfo[probe].index))
 | 
			
		||||
				tmp = probe;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Fit the rate found to the nearest supported rate. */
 | 
			
		||||
	do {
 | 
			
		||||
		if (rate_supported(sta, band, rinfo[tmp].index)) {
 | 
			
		||||
			sta->txrate_idx = rinfo[tmp].index;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (adj < 0)
 | 
			
		||||
			tmp--;
 | 
			
		||||
		else
 | 
			
		||||
			tmp++;
 | 
			
		||||
	} while (tmp < n_bitrates && tmp >= 0);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	rate_control_pid_event_rate_change(
 | 
			
		||||
		&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
 | 
			
		||||
		sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Normalize the failed frames per-rate differences. */
 | 
			
		||||
static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l)
 | 
			
		||||
{
 | 
			
		||||
	int i, norm_offset = pinfo->norm_offset;
 | 
			
		||||
	struct rc_pid_rateinfo *r = pinfo->rinfo;
 | 
			
		||||
 | 
			
		||||
	if (r[0].diff > norm_offset)
 | 
			
		||||
		r[0].diff -= norm_offset;
 | 
			
		||||
	else if (r[0].diff < -norm_offset)
 | 
			
		||||
		r[0].diff += norm_offset;
 | 
			
		||||
	for (i = 0; i < l - 1; i++)
 | 
			
		||||
		if (r[i + 1].diff > r[i].diff + norm_offset)
 | 
			
		||||
			r[i + 1].diff -= norm_offset;
 | 
			
		||||
		else if (r[i + 1].diff <= r[i].diff)
 | 
			
		||||
			r[i + 1].diff += norm_offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 | 
			
		||||
				    struct ieee80211_local *local,
 | 
			
		||||
				    struct sta_info *sta)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
 | 
			
		||||
	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
	u32 pf;
 | 
			
		||||
	s32 err_avg;
 | 
			
		||||
	u32 err_prop;
 | 
			
		||||
	u32 err_int;
 | 
			
		||||
	u32 err_der;
 | 
			
		||||
	int adj, i, j, tmp;
 | 
			
		||||
	unsigned long period;
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
	spinfo = sta->rate_ctrl_priv;
 | 
			
		||||
 | 
			
		||||
	/* In case nothing happened during the previous control interval, turn
 | 
			
		||||
	 * the sharpening factor on. */
 | 
			
		||||
	period = (HZ * pinfo->sampling_period + 500) / 1000;
 | 
			
		||||
	if (!period)
 | 
			
		||||
		period = 1;
 | 
			
		||||
	if (jiffies - spinfo->last_sample > 2 * period)
 | 
			
		||||
		spinfo->sharp_cnt = pinfo->sharpen_duration;
 | 
			
		||||
 | 
			
		||||
	spinfo->last_sample = jiffies;
 | 
			
		||||
 | 
			
		||||
	/* This should never happen, but in case, we assume the old sample is
 | 
			
		||||
	 * still a good measurement and copy it. */
 | 
			
		||||
	if (unlikely(spinfo->tx_num_xmit == 0))
 | 
			
		||||
		pf = spinfo->last_pf;
 | 
			
		||||
	else {
 | 
			
		||||
		pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
 | 
			
		||||
		pf <<= RC_PID_ARITH_SHIFT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spinfo->tx_num_xmit = 0;
 | 
			
		||||
	spinfo->tx_num_failed = 0;
 | 
			
		||||
 | 
			
		||||
	/* If we just switched rate, update the rate behaviour info. */
 | 
			
		||||
	if (pinfo->oldrate != sta->txrate_idx) {
 | 
			
		||||
 | 
			
		||||
		i = rinfo[pinfo->oldrate].rev_index;
 | 
			
		||||
		j = rinfo[sta->txrate_idx].rev_index;
 | 
			
		||||
 | 
			
		||||
		tmp = (pf - spinfo->last_pf);
 | 
			
		||||
		tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
 | 
			
		||||
 | 
			
		||||
		rinfo[j].diff = rinfo[i].diff + tmp;
 | 
			
		||||
		pinfo->oldrate = sta->txrate_idx;
 | 
			
		||||
	}
 | 
			
		||||
	rate_control_pid_normalize(pinfo, sband->n_bitrates);
 | 
			
		||||
 | 
			
		||||
	/* Compute the proportional, integral and derivative errors. */
 | 
			
		||||
	err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf;
 | 
			
		||||
 | 
			
		||||
	err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift;
 | 
			
		||||
	spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop;
 | 
			
		||||
	err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift;
 | 
			
		||||
 | 
			
		||||
	err_der = (pf - spinfo->last_pf) *
 | 
			
		||||
		  (1 + pinfo->sharpen_factor * spinfo->sharp_cnt);
 | 
			
		||||
	spinfo->last_pf = pf;
 | 
			
		||||
	if (spinfo->sharp_cnt)
 | 
			
		||||
			spinfo->sharp_cnt--;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int,
 | 
			
		||||
					 err_der);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Compute the controller output. */
 | 
			
		||||
	adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i
 | 
			
		||||
	      + err_der * pinfo->coeff_d);
 | 
			
		||||
	adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT);
 | 
			
		||||
 | 
			
		||||
	/* Change rate. */
 | 
			
		||||
	if (adj)
 | 
			
		||||
		rate_control_pid_adjust_rate(local, sta, adj, rinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 | 
			
		||||
				       struct sk_buff *skb,
 | 
			
		||||
				       struct ieee80211_tx_status *status)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 | 
			
		||||
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	struct rc_pid_info *pinfo = priv;
 | 
			
		||||
	struct sta_info *sta;
 | 
			
		||||
	struct rc_pid_sta_info *spinfo;
 | 
			
		||||
	unsigned long period;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
 | 
			
		||||
	sta = sta_info_get(local, hdr->addr1);
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
 | 
			
		||||
	if (!sta)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Don't update the state if we're not controlling the rate. */
 | 
			
		||||
	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 | 
			
		||||
	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
 | 
			
		||||
		sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ignore all frames that were sent with a different rate than the rate
 | 
			
		||||
	 * we currently advise mac80211 to use. */
 | 
			
		||||
	if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
 | 
			
		||||
		goto ignore;
 | 
			
		||||
 | 
			
		||||
	spinfo = sta->rate_ctrl_priv;
 | 
			
		||||
	spinfo->tx_num_xmit++;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	rate_control_pid_event_tx_status(&spinfo->events, status);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* We count frames that totally failed to be transmitted as two bad
 | 
			
		||||
	 * frames, those that made it out but had some retries as one good and
 | 
			
		||||
	 * one bad frame. */
 | 
			
		||||
	if (status->excessive_retries) {
 | 
			
		||||
		spinfo->tx_num_failed += 2;
 | 
			
		||||
		spinfo->tx_num_xmit++;
 | 
			
		||||
	} else if (status->retry_count) {
 | 
			
		||||
		spinfo->tx_num_failed++;
 | 
			
		||||
		spinfo->tx_num_xmit++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (status->excessive_retries) {
 | 
			
		||||
		sta->tx_retry_failed++;
 | 
			
		||||
		sta->tx_num_consecutive_failures++;
 | 
			
		||||
		sta->tx_num_mpdu_fail++;
 | 
			
		||||
	} else {
 | 
			
		||||
		sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
 | 
			
		||||
		sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
 | 
			
		||||
		sta->last_ack_rssi[2] = status->ack_signal;
 | 
			
		||||
		sta->tx_num_consecutive_failures = 0;
 | 
			
		||||
		sta->tx_num_mpdu_ok++;
 | 
			
		||||
	}
 | 
			
		||||
	sta->tx_retry_count += status->retry_count;
 | 
			
		||||
	sta->tx_num_mpdu_fail += status->retry_count;
 | 
			
		||||
 | 
			
		||||
	/* Update PID controller state. */
 | 
			
		||||
	period = (HZ * pinfo->sampling_period + 500) / 1000;
 | 
			
		||||
	if (!period)
 | 
			
		||||
		period = 1;
 | 
			
		||||
	if (time_after(jiffies, spinfo->last_sample + period))
 | 
			
		||||
		rate_control_pid_sample(pinfo, local, sta);
 | 
			
		||||
 | 
			
		||||
ignore:
 | 
			
		||||
	sta_info_put(sta);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 | 
			
		||||
				      struct ieee80211_supported_band *sband,
 | 
			
		||||
				      struct sk_buff *skb,
 | 
			
		||||
				      struct rate_selection *sel)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 | 
			
		||||
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	struct sta_info *sta;
 | 
			
		||||
	int rateidx;
 | 
			
		||||
	u16 fc;
 | 
			
		||||
 | 
			
		||||
	sta = sta_info_get(local, hdr->addr1);
 | 
			
		||||
 | 
			
		||||
	/* Send management frames and broadcast/multicast data using lowest
 | 
			
		||||
	 * rate. */
 | 
			
		||||
	fc = le16_to_cpu(hdr->frame_control);
 | 
			
		||||
	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
 | 
			
		||||
	    is_multicast_ether_addr(hdr->addr1) || !sta) {
 | 
			
		||||
		sel->rate = rate_lowest(local, sband, sta);
 | 
			
		||||
		if (sta)
 | 
			
		||||
			sta_info_put(sta);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If a forced rate is in effect, select it. */
 | 
			
		||||
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
			
		||||
	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
 | 
			
		||||
		sta->txrate_idx = sdata->bss->force_unicast_rateidx;
 | 
			
		||||
 | 
			
		||||
	rateidx = sta->txrate_idx;
 | 
			
		||||
 | 
			
		||||
	if (rateidx >= sband->n_bitrates)
 | 
			
		||||
		rateidx = sband->n_bitrates - 1;
 | 
			
		||||
 | 
			
		||||
	sta->last_txrate_idx = rateidx;
 | 
			
		||||
 | 
			
		||||
	sta_info_put(sta);
 | 
			
		||||
 | 
			
		||||
	sel->rate = &sband->bitrates[rateidx];
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	rate_control_pid_event_tx_rate(
 | 
			
		||||
		&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
 | 
			
		||||
		rateidx, sband->bitrates[rateidx].bitrate);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_rate_init(void *priv, void *priv_sta,
 | 
			
		||||
					  struct ieee80211_local *local,
 | 
			
		||||
					  struct sta_info *sta)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: This routine should consider using RSSI from previous packets
 | 
			
		||||
	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
 | 
			
		||||
	 * Until that method is implemented, we will use the lowest supported
 | 
			
		||||
	 * rate as a workaround. */
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
	sta->txrate_idx = rate_lowest_index(local, sband, sta);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *rate_control_pid_alloc(struct ieee80211_local *local)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_info *pinfo;
 | 
			
		||||
	struct rc_pid_rateinfo *rinfo;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
	int i, j, tmp;
 | 
			
		||||
	bool s;
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	struct rc_pid_debugfs_entries *de;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
 | 
			
		||||
	pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
 | 
			
		||||
	if (!pinfo)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* We can safely assume that sband won't change unless we get
 | 
			
		||||
	 * reinitialized. */
 | 
			
		||||
	rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
 | 
			
		||||
	if (!rinfo) {
 | 
			
		||||
		kfree(pinfo);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Sort the rates. This is optimized for the most common case (i.e.
 | 
			
		||||
	 * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
 | 
			
		||||
	 * mapping too. */
 | 
			
		||||
	for (i = 0; i < sband->n_bitrates; i++) {
 | 
			
		||||
		rinfo[i].index = i;
 | 
			
		||||
		rinfo[i].rev_index = i;
 | 
			
		||||
		if (pinfo->fast_start)
 | 
			
		||||
			rinfo[i].diff = 0;
 | 
			
		||||
		else
 | 
			
		||||
			rinfo[i].diff = i * pinfo->norm_offset;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 1; i < sband->n_bitrates; i++) {
 | 
			
		||||
		s = 0;
 | 
			
		||||
		for (j = 0; j < sband->n_bitrates - i; j++)
 | 
			
		||||
			if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
 | 
			
		||||
				     sband->bitrates[rinfo[j + 1].index].bitrate)) {
 | 
			
		||||
				tmp = rinfo[j].index;
 | 
			
		||||
				rinfo[j].index = rinfo[j + 1].index;
 | 
			
		||||
				rinfo[j + 1].index = tmp;
 | 
			
		||||
				rinfo[rinfo[j].index].rev_index = j;
 | 
			
		||||
				rinfo[rinfo[j + 1].index].rev_index = j + 1;
 | 
			
		||||
				s = 1;
 | 
			
		||||
			}
 | 
			
		||||
		if (!s)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pinfo->target = RC_PID_TARGET_PF;
 | 
			
		||||
	pinfo->sampling_period = RC_PID_INTERVAL;
 | 
			
		||||
	pinfo->coeff_p = RC_PID_COEFF_P;
 | 
			
		||||
	pinfo->coeff_i = RC_PID_COEFF_I;
 | 
			
		||||
	pinfo->coeff_d = RC_PID_COEFF_D;
 | 
			
		||||
	pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
 | 
			
		||||
	pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
 | 
			
		||||
	pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
 | 
			
		||||
	pinfo->norm_offset = RC_PID_NORM_OFFSET;
 | 
			
		||||
	pinfo->fast_start = RC_PID_FAST_START;
 | 
			
		||||
	pinfo->rinfo = rinfo;
 | 
			
		||||
	pinfo->oldrate = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	de = &pinfo->dentries;
 | 
			
		||||
	de->dir = debugfs_create_dir("rc80211_pid",
 | 
			
		||||
				     local->hw.wiphy->debugfsdir);
 | 
			
		||||
	de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
 | 
			
		||||
					de->dir, &pinfo->target);
 | 
			
		||||
	de->sampling_period = debugfs_create_u32("sampling_period",
 | 
			
		||||
						 S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
						 &pinfo->sampling_period);
 | 
			
		||||
	de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
 | 
			
		||||
					 de->dir, &pinfo->coeff_p);
 | 
			
		||||
	de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
 | 
			
		||||
					 de->dir, &pinfo->coeff_i);
 | 
			
		||||
	de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
 | 
			
		||||
					 de->dir, &pinfo->coeff_d);
 | 
			
		||||
	de->smoothing_shift = debugfs_create_u32("smoothing_shift",
 | 
			
		||||
						 S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
						 &pinfo->smoothing_shift);
 | 
			
		||||
	de->sharpen_factor = debugfs_create_u32("sharpen_factor",
 | 
			
		||||
					       S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
					       &pinfo->sharpen_factor);
 | 
			
		||||
	de->sharpen_duration = debugfs_create_u32("sharpen_duration",
 | 
			
		||||
						  S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
						  &pinfo->sharpen_duration);
 | 
			
		||||
	de->norm_offset = debugfs_create_u32("norm_offset",
 | 
			
		||||
					     S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
					     &pinfo->norm_offset);
 | 
			
		||||
	de->fast_start = debugfs_create_bool("fast_start",
 | 
			
		||||
					     S_IRUSR | S_IWUSR, de->dir,
 | 
			
		||||
					     &pinfo->fast_start);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return pinfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_free(void *priv)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_info *pinfo = priv;
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	struct rc_pid_debugfs_entries *de = &pinfo->dentries;
 | 
			
		||||
 | 
			
		||||
	debugfs_remove(de->fast_start);
 | 
			
		||||
	debugfs_remove(de->norm_offset);
 | 
			
		||||
	debugfs_remove(de->sharpen_duration);
 | 
			
		||||
	debugfs_remove(de->sharpen_factor);
 | 
			
		||||
	debugfs_remove(de->smoothing_shift);
 | 
			
		||||
	debugfs_remove(de->coeff_d);
 | 
			
		||||
	debugfs_remove(de->coeff_i);
 | 
			
		||||
	debugfs_remove(de->coeff_p);
 | 
			
		||||
	debugfs_remove(de->sampling_period);
 | 
			
		||||
	debugfs_remove(de->target);
 | 
			
		||||
	debugfs_remove(de->dir);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	kfree(pinfo->rinfo);
 | 
			
		||||
	kfree(pinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_clear(void *priv)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *spinfo;
 | 
			
		||||
 | 
			
		||||
	spinfo = kzalloc(sizeof(*spinfo), gfp);
 | 
			
		||||
	if (spinfo == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	spinfo->last_sample = jiffies;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	spin_lock_init(&spinfo->events.lock);
 | 
			
		||||
	init_waitqueue_head(&spinfo->events.waitqueue);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return spinfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_free_sta(void *priv, void *priv_sta)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *spinfo = priv_sta;
 | 
			
		||||
	kfree(spinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct rate_control_ops mac80211_rcpid = {
 | 
			
		||||
	.name = "pid",
 | 
			
		||||
	.tx_status = rate_control_pid_tx_status,
 | 
			
		||||
	.get_rate = rate_control_pid_get_rate,
 | 
			
		||||
	.rate_init = rate_control_pid_rate_init,
 | 
			
		||||
	.clear = rate_control_pid_clear,
 | 
			
		||||
	.alloc = rate_control_pid_alloc,
 | 
			
		||||
	.free = rate_control_pid_free,
 | 
			
		||||
	.alloc_sta = rate_control_pid_alloc_sta,
 | 
			
		||||
	.free_sta = rate_control_pid_free_sta,
 | 
			
		||||
#ifdef CONFIG_MAC80211_DEBUGFS
 | 
			
		||||
	.add_sta_debugfs = rate_control_pid_add_sta_debugfs,
 | 
			
		||||
	.remove_sta_debugfs = rate_control_pid_remove_sta_debugfs,
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION("PID controller based rate control algorithm");
 | 
			
		||||
MODULE_AUTHOR("Stefano Brivio");
 | 
			
		||||
MODULE_AUTHOR("Mattias Nissler");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
 | 
			
		||||
int __init rc80211_pid_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return ieee80211_rate_control_register(&mac80211_rcpid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rc80211_pid_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	ieee80211_rate_control_unregister(&mac80211_rcpid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MAC80211_RC_PID_MODULE
 | 
			
		||||
module_init(rc80211_pid_init);
 | 
			
		||||
module_exit(rc80211_pid_exit);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										223
									
								
								package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,223 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/poll.h>
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
 | 
			
		||||
#include <net/mac80211.h>
 | 
			
		||||
#include "ieee80211_rate.h"
 | 
			
		||||
 | 
			
		||||
#include "rc80211_pid.h"
 | 
			
		||||
 | 
			
		||||
static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
 | 
			
		||||
				   enum rc_pid_event_type type,
 | 
			
		||||
				   union rc_pid_event_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_event *ev;
 | 
			
		||||
	unsigned long status;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&buf->lock, status);
 | 
			
		||||
	ev = &(buf->ring[buf->next_entry]);
 | 
			
		||||
	buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE;
 | 
			
		||||
 | 
			
		||||
	ev->timestamp = jiffies;
 | 
			
		||||
	ev->id = buf->ev_count++;
 | 
			
		||||
	ev->type = type;
 | 
			
		||||
	ev->data = *data;
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&buf->lock, status);
 | 
			
		||||
 | 
			
		||||
	wake_up_all(&buf->waitqueue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					     struct ieee80211_tx_status *stat)
 | 
			
		||||
{
 | 
			
		||||
	union rc_pid_event_data evd;
 | 
			
		||||
 | 
			
		||||
	memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
 | 
			
		||||
	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					       int index, int rate)
 | 
			
		||||
{
 | 
			
		||||
	union rc_pid_event_data evd;
 | 
			
		||||
 | 
			
		||||
	evd.index = index;
 | 
			
		||||
	evd.rate = rate;
 | 
			
		||||
	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					   int index, int rate)
 | 
			
		||||
{
 | 
			
		||||
	union rc_pid_event_data evd;
 | 
			
		||||
 | 
			
		||||
	evd.index = index;
 | 
			
		||||
	evd.rate = rate;
 | 
			
		||||
	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
 | 
			
		||||
					     s32 pf_sample, s32 prop_err,
 | 
			
		||||
					     s32 int_err, s32 der_err)
 | 
			
		||||
{
 | 
			
		||||
	union rc_pid_event_data evd;
 | 
			
		||||
 | 
			
		||||
	evd.pf_sample = pf_sample;
 | 
			
		||||
	evd.prop_err = prop_err;
 | 
			
		||||
	evd.int_err = int_err;
 | 
			
		||||
	evd.der_err = der_err;
 | 
			
		||||
	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rate_control_pid_events_open(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *sinfo = inode->i_private;
 | 
			
		||||
	struct rc_pid_event_buffer *events = &sinfo->events;
 | 
			
		||||
	struct rc_pid_events_file_info *file_info;
 | 
			
		||||
	unsigned int status;
 | 
			
		||||
 | 
			
		||||
	/* Allocate a state struct */
 | 
			
		||||
	file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
 | 
			
		||||
	if (file_info == NULL)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&events->lock, status);
 | 
			
		||||
 | 
			
		||||
	file_info->next_entry = events->next_entry;
 | 
			
		||||
	file_info->events = events;
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&events->lock, status);
 | 
			
		||||
 | 
			
		||||
	file->private_data = file_info;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rate_control_pid_events_release(struct inode *inode,
 | 
			
		||||
					   struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_events_file_info *file_info = file->private_data;
 | 
			
		||||
 | 
			
		||||
	kfree(file_info);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int rate_control_pid_events_poll(struct file *file,
 | 
			
		||||
						 poll_table *wait)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_events_file_info *file_info = file->private_data;
 | 
			
		||||
 | 
			
		||||
	poll_wait(file, &file_info->events->waitqueue, wait);
 | 
			
		||||
 | 
			
		||||
	return POLLIN | POLLRDNORM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define RC_PID_PRINT_BUF_SIZE 64
 | 
			
		||||
 | 
			
		||||
static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
 | 
			
		||||
					    size_t length, loff_t *offset)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_events_file_info *file_info = file->private_data;
 | 
			
		||||
	struct rc_pid_event_buffer *events = file_info->events;
 | 
			
		||||
	struct rc_pid_event *ev;
 | 
			
		||||
	char pb[RC_PID_PRINT_BUF_SIZE];
 | 
			
		||||
	int ret;
 | 
			
		||||
	int p;
 | 
			
		||||
	unsigned int status;
 | 
			
		||||
 | 
			
		||||
	/* Check if there is something to read. */
 | 
			
		||||
	if (events->next_entry == file_info->next_entry) {
 | 
			
		||||
		if (file->f_flags & O_NONBLOCK)
 | 
			
		||||
			return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
		/* Wait */
 | 
			
		||||
		ret = wait_event_interruptible(events->waitqueue,
 | 
			
		||||
				events->next_entry != file_info->next_entry);
 | 
			
		||||
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Write out one event per call. I don't care whether it's a little
 | 
			
		||||
	 * inefficient, this is debugging code anyway. */
 | 
			
		||||
	spin_lock_irqsave(&events->lock, status);
 | 
			
		||||
 | 
			
		||||
	/* Get an event */
 | 
			
		||||
	ev = &(events->ring[file_info->next_entry]);
 | 
			
		||||
	file_info->next_entry = (file_info->next_entry + 1) %
 | 
			
		||||
				RC_PID_EVENT_RING_SIZE;
 | 
			
		||||
 | 
			
		||||
	/* Print information about the event. Note that userpace needs to
 | 
			
		||||
	 * provide large enough buffers. */
 | 
			
		||||
	length = length < RC_PID_PRINT_BUF_SIZE ?
 | 
			
		||||
		 length : RC_PID_PRINT_BUF_SIZE;
 | 
			
		||||
	p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
 | 
			
		||||
	switch (ev->type) {
 | 
			
		||||
	case RC_PID_EVENT_TYPE_TX_STATUS:
 | 
			
		||||
		p += snprintf(pb + p, length - p, "tx_status %u %u",
 | 
			
		||||
			      ev->data.tx_status.excessive_retries,
 | 
			
		||||
			      ev->data.tx_status.retry_count);
 | 
			
		||||
		break;
 | 
			
		||||
	case RC_PID_EVENT_TYPE_RATE_CHANGE:
 | 
			
		||||
		p += snprintf(pb + p, length - p, "rate_change %d %d",
 | 
			
		||||
			      ev->data.index, ev->data.rate);
 | 
			
		||||
		break;
 | 
			
		||||
	case RC_PID_EVENT_TYPE_TX_RATE:
 | 
			
		||||
		p += snprintf(pb + p, length - p, "tx_rate %d %d",
 | 
			
		||||
			      ev->data.index, ev->data.rate);
 | 
			
		||||
		break;
 | 
			
		||||
	case RC_PID_EVENT_TYPE_PF_SAMPLE:
 | 
			
		||||
		p += snprintf(pb + p, length - p,
 | 
			
		||||
			      "pf_sample %d %d %d %d",
 | 
			
		||||
			      ev->data.pf_sample, ev->data.prop_err,
 | 
			
		||||
			      ev->data.int_err, ev->data.der_err);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	p += snprintf(pb + p, length - p, "\n");
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&events->lock, status);
 | 
			
		||||
 | 
			
		||||
	if (copy_to_user(buf, pb, p))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#undef RC_PID_PRINT_BUF_SIZE
 | 
			
		||||
 | 
			
		||||
static struct file_operations rc_pid_fop_events = {
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.read = rate_control_pid_events_read,
 | 
			
		||||
	.poll = rate_control_pid_events_poll,
 | 
			
		||||
	.open = rate_control_pid_events_open,
 | 
			
		||||
	.release = rate_control_pid_events_release,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
 | 
			
		||||
					     struct dentry *dir)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *spinfo = priv_sta;
 | 
			
		||||
 | 
			
		||||
	spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO,
 | 
			
		||||
						   dir, spinfo,
 | 
			
		||||
						   &rc_pid_fop_events);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta)
 | 
			
		||||
{
 | 
			
		||||
	struct rc_pid_sta_info *spinfo = priv_sta;
 | 
			
		||||
 | 
			
		||||
	debugfs_remove(spinfo->events_entry);
 | 
			
		||||
}
 | 
			
		||||
@ -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 */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										153
									
								
								package/mac80211/src/net/wireless/reg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								package/mac80211/src/net/wireless/reg.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,153 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2002-2005, Instant802 Networks, Inc.
 | 
			
		||||
 * Copyright 2005-2006, Devicescape Software, Inc.
 | 
			
		||||
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This regulatory domain control implementation is highly incomplete, it
 | 
			
		||||
 * only exists for the purpose of not regressing mac80211.
 | 
			
		||||
 *
 | 
			
		||||
 * For now, drivers can restrict the set of allowed channels by either
 | 
			
		||||
 * not registering those channels or setting the IEEE80211_CHAN_DISABLED
 | 
			
		||||
 * flag; that flag will only be *set* by this code, never *cleared.
 | 
			
		||||
 *
 | 
			
		||||
 * The usual implementation is for a driver to read a device EEPROM to
 | 
			
		||||
 * determine which regulatory domain it should be operating under, then
 | 
			
		||||
 * looking up the allowable channels in a driver-local table and finally
 | 
			
		||||
 * registering those channels in the wiphy structure.
 | 
			
		||||
 *
 | 
			
		||||
 * Alternatively, drivers that trust the regulatory domain control here
 | 
			
		||||
 * will register a complete set of capabilities and the control code
 | 
			
		||||
 * will restrict the set by setting the IEEE80211_CHAN_* flags.
 | 
			
		||||
 */
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <net/wireless.h>
 | 
			
		||||
#include "core.h"
 | 
			
		||||
 | 
			
		||||
static char *ieee80211_regdom = "US";
 | 
			
		||||
module_param(ieee80211_regdom, charp, 0444);
 | 
			
		||||
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 | 
			
		||||
 | 
			
		||||
struct ieee80211_channel_range {
 | 
			
		||||
	short start_freq;
 | 
			
		||||
	short end_freq;
 | 
			
		||||
	int max_power;
 | 
			
		||||
	int max_antenna_gain;
 | 
			
		||||
	u32 flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ieee80211_regdomain {
 | 
			
		||||
	const char *code;
 | 
			
		||||
	const struct ieee80211_channel_range *ranges;
 | 
			
		||||
	int n_ranges;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RANGE_PWR(_start, _end, _pwr, _ag, _flags)	\
 | 
			
		||||
	{ _start, _end, _pwr, _ag, _flags }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Ideally, in the future, these definitions will be loaded from a
 | 
			
		||||
 * userspace table via some daemon.
 | 
			
		||||
 */
 | 
			
		||||
static const struct ieee80211_channel_range ieee80211_US_channels[] = {
 | 
			
		||||
	/* IEEE 802.11b/g, channels 1..11 */
 | 
			
		||||
	RANGE_PWR(2412, 2462, 27, 6, 0),
 | 
			
		||||
	/* IEEE 802.11a, channels 52..64 */
 | 
			
		||||
	RANGE_PWR(5260, 5320, 23, 6, 0),
 | 
			
		||||
	/* IEEE 802.11a, channels 149..165, outdoor */
 | 
			
		||||
	RANGE_PWR(5745, 5825, 30, 6, 0),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
 | 
			
		||||
	/* IEEE 802.11b/g, channels 1..14 */
 | 
			
		||||
	RANGE_PWR(2412, 2484, 20, 6, 0),
 | 
			
		||||
	/* IEEE 802.11a, channels 34..48 */
 | 
			
		||||
	RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
 | 
			
		||||
	/* IEEE 802.11a, channels 52..64 */
 | 
			
		||||
	RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
 | 
			
		||||
				     IEEE80211_CHAN_RADAR),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define REGDOM(_code)							\
 | 
			
		||||
	{								\
 | 
			
		||||
		.code = __stringify(_code),				\
 | 
			
		||||
		.ranges = ieee80211_ ##_code## _channels,		\
 | 
			
		||||
		.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels),	\
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
static const struct ieee80211_regdomain ieee80211_regdoms[] = {
 | 
			
		||||
	REGDOM(US),
 | 
			
		||||
	REGDOM(JP),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct ieee80211_regdomain *get_regdom(void)
 | 
			
		||||
{
 | 
			
		||||
	static const struct ieee80211_channel_range
 | 
			
		||||
	ieee80211_world_channels[] = {
 | 
			
		||||
		/* IEEE 802.11b/g, channels 1..11 */
 | 
			
		||||
		RANGE_PWR(2412, 2462, 27, 6, 0),
 | 
			
		||||
	};
 | 
			
		||||
	static const struct ieee80211_regdomain regdom_world = REGDOM(world);
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
 | 
			
		||||
		if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
 | 
			
		||||
			return &ieee80211_regdoms[i];
 | 
			
		||||
 | 
			
		||||
	return ®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
	
	Block a user