summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/mac80211-injection.txt28
-rw-r--r--Documentation/rfkill.txt16
-rw-r--r--MAINTAINERS10
-rw-r--r--arch/arm/mach-pxa/tosa-bt.c4
-rw-r--r--drivers/net/usb/hso.c4
-rw-r--r--drivers/net/wireless/Kconfig16
-rw-r--r--drivers/net/wireless/Makefile4
-rw-r--r--drivers/net/wireless/at76c50x-usb.c1
-rw-r--r--drivers/net/wireless/ath/Kconfig8
-rw-r--r--drivers/net/wireless/ath/Makefile6
-rw-r--r--drivers/net/wireless/ath/ar9170/Kconfig (renamed from drivers/net/wireless/ar9170/Kconfig)1
-rw-r--r--drivers/net/wireless/ath/ar9170/Makefile (renamed from drivers/net/wireless/ar9170/Makefile)0
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h (renamed from drivers/net/wireless/ar9170/ar9170.h)32
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c (renamed from drivers/net/wireless/ar9170/cmd.c)0
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.h (renamed from drivers/net/wireless/ar9170/cmd.h)0
-rw-r--r--drivers/net/wireless/ath/ar9170/eeprom.h (renamed from drivers/net/wireless/ar9170/eeprom.h)0
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h (renamed from drivers/net/wireless/ar9170/hw.h)15
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c (renamed from drivers/net/wireless/ar9170/led.c)0
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c (renamed from drivers/net/wireless/ar9170/mac.c)0
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c (renamed from drivers/net/wireless/ar9170/main.c)613
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c (renamed from drivers/net/wireless/ar9170/phy.c)0
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c (renamed from drivers/net/wireless/ar9170/usb.c)0
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h (renamed from drivers/net/wireless/ar9170/usb.h)2
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig (renamed from drivers/net/wireless/ath5k/Kconfig)1
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile (renamed from drivers/net/wireless/ath5k/Makefile)0
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h (renamed from drivers/net/wireless/ath5k/ath5k.h)5
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c (renamed from drivers/net/wireless/ath5k/attach.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c (renamed from drivers/net/wireless/ath5k/base.c)74
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h (renamed from drivers/net/wireless/ath5k/base.h)1
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c (renamed from drivers/net/wireless/ath5k/caps.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c (renamed from drivers/net/wireless/ath5k/debug.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h (renamed from drivers/net/wireless/ath5k/debug.h)0
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c (renamed from drivers/net/wireless/ath5k/desc.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.h (renamed from drivers/net/wireless/ath5k/desc.h)0
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c (renamed from drivers/net/wireless/ath5k/dma.c)2
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c (renamed from drivers/net/wireless/ath5k/eeprom.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h (renamed from drivers/net/wireless/ath5k/eeprom.h)0
-rw-r--r--drivers/net/wireless/ath/ath5k/gpio.c (renamed from drivers/net/wireless/ath5k/gpio.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c (renamed from drivers/net/wireless/ath5k/initvals.c)8
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c (renamed from drivers/net/wireless/ath5k/led.c)4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c (renamed from drivers/net/wireless/ath5k/pcu.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c (renamed from drivers/net/wireless/ath5k/phy.c)49
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c (renamed from drivers/net/wireless/ath5k/qcu.c)0
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h (renamed from drivers/net/wireless/ath5k/reg.h)0
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c (renamed from drivers/net/wireless/ath5k/reset.c)2
-rw-r--r--drivers/net/wireless/ath/ath5k/rfbuffer.h (renamed from drivers/net/wireless/ath5k/rfbuffer.h)0
-rw-r--r--drivers/net/wireless/ath/ath5k/rfgain.h (renamed from drivers/net/wireless/ath5k/rfgain.h)0
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig (renamed from drivers/net/wireless/ath9k/Kconfig)1
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile (renamed from drivers/net/wireless/ath9k/Makefile)1
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c (renamed from drivers/net/wireless/ath9k/ahb.c)0
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c (renamed from drivers/net/wireless/ath9k/ani.c)8
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h (renamed from drivers/net/wireless/ath9k/ani.h)0
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h (renamed from drivers/net/wireless/ath9k/ath9k.h)65
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c (renamed from drivers/net/wireless/ath9k/beacon.c)17
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c (renamed from drivers/net/wireless/ath9k/calib.c)123
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h (renamed from drivers/net/wireless/ath9k/calib.h)33
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c (renamed from drivers/net/wireless/ath9k/debug.c)3
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h (renamed from drivers/net/wireless/ath9k/debug.h)24
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c (renamed from drivers/net/wireless/ath9k/eeprom.c)24
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h (renamed from drivers/net/wireless/ath9k/eeprom.h)2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c (renamed from drivers/net/wireless/ath9k/hw.c)179
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h (renamed from drivers/net/wireless/ath9k/hw.h)90
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h (renamed from drivers/net/wireless/ath9k/initvals.h)0
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c (renamed from drivers/net/wireless/ath9k/mac.c)63
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h (renamed from drivers/net/wireless/ath9k/mac.h)0
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c (renamed from drivers/net/wireless/ath9k/main.c)374
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c (renamed from drivers/net/wireless/ath9k/pci.c)0
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c (renamed from drivers/net/wireless/ath9k/phy.c)4
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h (renamed from drivers/net/wireless/ath9k/phy.h)3
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c (renamed from drivers/net/wireless/ath9k/rc.c)26
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h (renamed from drivers/net/wireless/ath9k/rc.h)4
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c (renamed from drivers/net/wireless/ath9k/recv.c)85
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h (renamed from drivers/net/wireless/ath9k/reg.h)0
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c (renamed from drivers/net/wireless/ath9k/virtual.c)0
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c (renamed from drivers/net/wireless/ath9k/xmit.c)64
-rw-r--r--drivers/net/wireless/ath/main.c22
-rw-r--r--drivers/net/wireless/ath/regd.c (renamed from drivers/net/wireless/ath9k/regd.c)241
-rw-r--r--drivers/net/wireless/ath/regd.h (renamed from drivers/net/wireless/ath9k/regd.h)40
-rw-r--r--drivers/net/wireless/ath/regd_common.h (renamed from drivers/net/wireless/ath9k/regd_common.h)0
-rw-r--r--drivers/net/wireless/b43/Kconfig8
-rw-r--r--drivers/net/wireless/b43/b43.h8
-rw-r--r--drivers/net/wireless/b43/main.c69
-rw-r--r--drivers/net/wireless/b43/rfkill.c1
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig8
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h8
-rw-r--r--drivers/net/wireless/b43legacy/main.c193
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c1
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c2
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h4
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c206
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c410
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c791
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c751
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h59
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c96
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c196
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c1017
-rw-r--r--drivers/net/wireless/libertas/cmd.c26
-rw-r--r--drivers/net/wireless/libertas/defs.h21
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/host.h3
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h28
-rw-r--r--drivers/net/wireless/libertas/if_cs.c34
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c17
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h2
-rw-r--r--drivers/net/wireless/libertas/if_spi.c6
-rw-r--r--drivers/net/wireless/libertas/main.c44
-rw-r--r--drivers/net/wireless/libertas/rx.c48
-rw-r--r--drivers/net/wireless/libertas/tx.c8
-rw-r--r--drivers/net/wireless/libertas/types.h2
-rw-r--r--drivers/net/wireless/p54/p54.h78
-rw-r--r--drivers/net/wireless/p54/p54common.c216
-rw-r--r--drivers/net/wireless/p54/p54spi.c127
-rw-r--r--drivers/net/wireless/rndis_wlan.c666
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h18
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c16
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h6
-rw-r--r--drivers/net/wireless/rtl818x/Makefile2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h7
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c21
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c218
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.h57
-rw-r--r--drivers/platform/x86/acer-wmi.c1
-rw-r--r--drivers/platform/x86/hp-wmi.c3
-rw-r--r--drivers/platform/x86/sony-laptop.c4
-rw-r--r--drivers/platform/x86/toshiba_acpi.c1
-rw-r--r--include/linux/ieee80211.h41
-rw-r--r--include/linux/mmc/sdio_ids.h2
-rw-r--r--include/linux/nl80211.h127
-rw-r--r--include/linux/pci_ids.h2
-rw-r--r--include/linux/rfkill.h14
-rw-r--r--include/net/cfg80211.h897
-rw-r--r--include/net/mac80211.h117
-rw-r--r--include/net/regulatory.h101
-rw-r--r--include/net/wireless.h472
-rw-r--r--net/mac80211/Kconfig16
-rw-r--r--net/mac80211/cfg.c59
-rw-r--r--net/mac80211/debugfs.c8
-rw-r--r--net/mac80211/event.c17
-rw-r--r--net/mac80211/ht.c84
-rw-r--r--net/mac80211/ibss.c347
-rw-r--r--net/mac80211/ieee80211_i.h85
-rw-r--r--net/mac80211/iface.c16
-rw-r--r--net/mac80211/main.c122
-rw-r--r--net/mac80211/mlme.c445
-rw-r--r--net/mac80211/pm.c121
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/scan.c28
-rw-r--r--net/mac80211/spectmgmt.c2
-rw-r--r--net/mac80211/sta_info.c71
-rw-r--r--net/mac80211/sta_info.h3
-rw-r--r--net/mac80211/tx.c35
-rw-r--r--net/mac80211/util.c240
-rw-r--r--net/mac80211/wext.c270
-rw-r--r--net/mac80211/wpa.c2
-rw-r--r--net/rfkill/rfkill-input.c69
-rw-r--r--net/rfkill/rfkill.c54
-rw-r--r--net/wimax/op-rfkill.c9
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c27
-rw-r--r--net/wireless/core.h15
-rw-r--r--net/wireless/ibss.c369
-rw-r--r--net/wireless/mlme.c50
-rw-r--r--net/wireless/nl80211.c639
-rw-r--r--net/wireless/nl80211.h32
-rw-r--r--net/wireless/reg.c35
-rw-r--r--net/wireless/scan.c53
-rw-r--r--net/wireless/util.c6
-rw-r--r--net/wireless/wext-compat.c236
187 files changed, 7859 insertions, 5549 deletions
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
index 84906ef3ed6..b30e81ad530 100644
--- a/Documentation/networking/mac80211-injection.txt
+++ b/Documentation/networking/mac80211-injection.txt
@@ -12,38 +12,22 @@ following format:
The radiotap format is discussed in
./Documentation/networking/radiotap-headers.txt.
-Despite 13 radiotap argument types are currently defined, most only make sense
+Despite many radiotap parameters being currently defined, most only make sense
to appear on received packets. The following information is parsed from the
radiotap headers and used to control injection:
- * IEEE80211_RADIOTAP_RATE
-
- rate in 500kbps units, automatic if invalid or not present
-
-
- * IEEE80211_RADIOTAP_ANTENNA
-
- antenna to use, automatic if not present
-
-
- * IEEE80211_RADIOTAP_DBM_TX_POWER
-
- transmit power in dBm, automatic if not present
-
-
* IEEE80211_RADIOTAP_FLAGS
IEEE80211_RADIOTAP_F_FCS: FCS will be removed and recalculated
IEEE80211_RADIOTAP_F_WEP: frame will be encrypted if key available
IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
- current fragmentation threshold. Note that
- this flag is only reliable when software
- fragmentation is enabled)
+ current fragmentation threshold.
+
The injection code can also skip all other currently defined radiotap fields
facilitating replay of captured radiotap headers directly.
-Here is an example valid radiotap header defining these three parameters
+Here is an example valid radiotap header defining some parameters
0x00, 0x00, // <-- radiotap version
0x0b, 0x00, // <- radiotap header length
@@ -72,8 +56,8 @@ interface), along the following lines:
...
r = pcap_inject(ppcap, u8aSendBuffer, nLength);
-You can also find sources for a complete inject test applet here:
+You can also find a link to a complete inject application here:
-http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer
+http://wireless.kernel.org/en/users/Documentation/packetspammer
Andy Green <andy@warmcat.com>
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index 4d3ee317a4a..40c3a3f1081 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -521,16 +521,12 @@ status of the system.
Input devices may issue events that are related to rfkill. These are the
various KEY_* events and SW_* events supported by rfkill-input.c.
-******IMPORTANT******
-When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL
-SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it
-has set to true the user_claim attribute for that particular switch. This rule
-is *absolute*; do NOT violate it.
-******IMPORTANT******
-
-Userspace must not assume it is the only source of control for rfkill switches.
-Their state CAN and WILL change due to firmware actions, direct user actions,
-and the rfkill-input EPO override for *_RFKILL_ALL.
+Userspace may not change the state of an rfkill switch in response to an
+input event, it should refrain from changing states entirely.
+
+Userspace cannot assume it is the only source of control for rfkill switches.
+Their state can change due to firmware actions, direct user actions, and the
+rfkill-input EPO override for *_RFKILL_ALL.
When rfkill-input is not active, userspace must initiate a rfkill status
change by writing to the "state" attribute in order for anything to happen.
diff --git a/MAINTAINERS b/MAINTAINERS
index 2dc197c362b..3dfe1a7c9a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -888,6 +888,12 @@ P: Luis R. Rodriguez
M: lrodriguez@atheros.com
P: Jouni Malinen
M: jmalinen@atheros.com
+P: Sujith Manoharan
+M: Sujith.Manoharan@atheros.com
+P: Vasanthakumar Thiagarajan
+M: vasanth@atheros.com
+P: Senthil Balasubramanian
+M: senthilkumar@atheros.com
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
S: Supported
@@ -4421,8 +4427,8 @@ S: Maintained
F: drivers/ata/sata_promise.*
PS3 NETWORK SUPPORT
-P: Masakazu Mokuno
-M: mokuno@sm.sony.co.jp
+P: Geoff Levand
+M: geoffrey.levand@am.sony.com
L: netdev@vger.kernel.org
L: cbe-oss-dev@ozlabs.org
S: Supported
diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c
index fb0294bd431..bde42aa2937 100644
--- a/arch/arm/mach-pxa/tosa-bt.c
+++ b/arch/arm/mach-pxa/tosa-bt.c
@@ -38,9 +38,9 @@ static void tosa_bt_off(struct tosa_bt_data *data)
static int tosa_bt_toggle_radio(void *data, enum rfkill_state state)
{
pr_info("BT_RADIO going: %s\n",
- state == RFKILL_STATE_ON ? "on" : "off");
+ state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
- if (state == RFKILL_STATE_ON) {
+ if (state == RFKILL_STATE_UNBLOCKED) {
pr_info("TOSA_BT: going ON\n");
tosa_bt_on(data);
} else {
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index f84b78d94c4..d696e5fbc17 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2484,7 +2484,7 @@ static int add_net_device(struct hso_device *hso_dev)
static int hso_radio_toggle(void *data, enum rfkill_state state)
{
struct hso_device *hso_dev = data;
- int enabled = (state == RFKILL_STATE_ON);
+ int enabled = (state == RFKILL_STATE_UNBLOCKED);
int rv;
mutex_lock(&hso_dev->mutex);
@@ -2522,7 +2522,7 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
snprintf(rfkn, 20, "hso-%d",
interface->altsetting->desc.bInterfaceNumber);
hso_net->rfkill->name = rfkn;
- hso_net->rfkill->state = RFKILL_STATE_ON;
+ hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
hso_net->rfkill->data = hso_dev;
hso_net->rfkill->toggle_radio = hso_radio_toggle;
if (rfkill_register(hso_net->rfkill) < 0) {
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 8a0823588c5..2d8434f409b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -146,10 +146,10 @@ config LIBERTAS_CS
A driver for Marvell Libertas 8385 CompactFlash devices.
config LIBERTAS_SDIO
- tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards"
+ tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
depends on LIBERTAS && MMC
---help---
- A driver for Marvell Libertas 8385 and 8686 SDIO devices.
+ A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
config LIBERTAS_SPI
tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
@@ -337,6 +337,7 @@ config USB_NET_RNDIS_WLAN
select USB_NET_CDCETHER
select USB_NET_RNDIS_HOST
select WIRELESS_EXT
+ select CFG80211
---help---
This is a driver for wireless RNDIS devices.
These are USB based adapters found in devices such as:
@@ -433,6 +434,13 @@ config RTL8187
Thanks to Realtek for their support!
+# If possible, automatically enable LEDs for RTL8187.
+
+config RTL8187_LEDS
+ bool
+ depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
+ default y
+
config ADM8211
tristate "ADMtek ADM8211 support"
depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
@@ -483,9 +491,7 @@ config MWL8K
will be called mwl8k. If unsure, say N.
source "drivers/net/wireless/p54/Kconfig"
-source "drivers/net/wireless/ath5k/Kconfig"
-source "drivers/net/wireless/ath9k/Kconfig"
-source "drivers/net/wireless/ar9170/Kconfig"
+source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/ipw2x00/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 50e7fba7f0e..0625e91b599 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -55,8 +55,6 @@ obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_P54_COMMON) += p54/
-obj-$(CONFIG_ATH5K) += ath5k/
-obj-$(CONFIG_ATH9K) += ath9k/
-obj-$(CONFIG_AR9170_USB) += ar9170/
+obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 69248ded510..55f947ac56d 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2250,6 +2250,7 @@ static int at76_init_new_device(struct at76_priv *priv,
/* mac80211 initialisation */
priv->hw->wiphy->max_scan_ssids = 1;
+ priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
new file mode 100644
index 00000000000..d26e7b48531
--- /dev/null
+++ b/drivers/net/wireless/ath/Kconfig
@@ -0,0 +1,8 @@
+config ATH_COMMON
+ tristate "Atheros Wireless Cards"
+ depends on ATH5K || ATH9K || AR9170_USB
+
+source "drivers/net/wireless/ath/ath5k/Kconfig"
+source "drivers/net/wireless/ath/ath9k/Kconfig"
+source "drivers/net/wireless/ath/ar9170/Kconfig"
+
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
new file mode 100644
index 00000000000..4bb0132ada3
--- /dev/null
+++ b/drivers/net/wireless/ath/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_ATH5K) += ath5k/
+obj-$(CONFIG_ATH9K) += ath9k/
+obj-$(CONFIG_AR9170_USB) += ar9170/
+
+obj-$(CONFIG_ATH_COMMON) += ath.o
+ath-objs := main.o regd.o
diff --git a/drivers/net/wireless/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig
index de4281fda12..b99e3263ee6 100644
--- a/drivers/net/wireless/ar9170/Kconfig
+++ b/drivers/net/wireless/ath/ar9170/Kconfig
@@ -2,6 +2,7 @@ config AR9170_USB
tristate "Atheros AR9170 802.11n USB support"
depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
+ select ATH_COMMON
help
This is a driver for the Atheros "otus" 802.11n USB devices.
diff --git a/drivers/net/wireless/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile
index 8d91c7ee321..8d91c7ee321 100644
--- a/drivers/net/wireless/ar9170/Makefile
+++ b/drivers/net/wireless/ath/ar9170/Makefile
diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index f4fb2e94aea..17bd3eaf3e0 100644
--- a/drivers/net/wireless/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -40,7 +40,7 @@
#include <linux/completion.h>
#include <linux/spinlock.h>
-#include <net/wireless.h>
+#include <net/cfg80211.h>
#include <net/mac80211.h>
#ifdef CONFIG_AR9170_LEDS
#include <linux/leds.h>
@@ -48,6 +48,8 @@
#include "eeprom.h"
#include "hw.h"
+#include "../regd.h"
+
#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1)
enum ar9170_bw {
@@ -58,6 +60,21 @@ enum ar9170_bw {
__AR9170_NUM_BW,
};
+static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type)
+{
+ switch (type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ return AR9170_BW_20;
+ case NL80211_CHAN_HT40MINUS:
+ return AR9170_BW_40_BELOW;
+ case NL80211_CHAN_HT40PLUS:
+ return AR9170_BW_40_ABOVE;
+ default:
+ BUG();
+ }
+}
+
enum ar9170_rf_init_mode {
AR9170_RFI_NONE,
AR9170_RFI_WARM,
@@ -87,10 +104,16 @@ enum ar9170_device_state {
AR9170_ASSOCIATED,
};
+struct ar9170_rxstream_mpdu_merge {
+ struct ar9170_rx_head plcp;
+ bool has_plcp;
+};
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
enum ar9170_device_state state;
+ unsigned long bad_hw_nagger;
int (*open)(struct ar9170 *);
void (*stop)(struct ar9170 *);
@@ -118,6 +141,7 @@ struct ar9170 {
u64 cur_mc_hash, want_mc_hash;
u32 cur_filter, want_filter;
unsigned int filter_changed;
+ unsigned int filter_state;
bool sniffer_enabled;
/* PHY */
@@ -151,11 +175,17 @@ struct ar9170 {
/* EEPROM */
struct ar9170_eeprom eeprom;
+ struct ath_regulatory regulatory;
/* global tx status for unregistered Stations. */
struct sk_buff_head global_tx_status;
struct sk_buff_head global_tx_status_waste;
struct delayed_work tx_status_janitor;
+
+ /* rxstream mpdu merge */
+ struct ar9170_rxstream_mpdu_merge rx_mpdu;
+ struct sk_buff *rx_failover;
+ int rx_failover_missing;
};
struct ar9170_sta_info {
diff --git a/drivers/net/wireless/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index f57a6200167..f57a6200167 100644
--- a/drivers/net/wireless/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
diff --git a/drivers/net/wireless/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h
index a4f0e50e52b..a4f0e50e52b 100644
--- a/drivers/net/wireless/ar9170/cmd.h
+++ b/drivers/net/wireless/ath/ar9170/cmd.h
diff --git a/drivers/net/wireless/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h
index d2c8cc83f1d..d2c8cc83f1d 100644
--- a/drivers/net/wireless/ar9170/eeprom.h
+++ b/drivers/net/wireless/ath/ar9170/eeprom.h
diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 53e250a4278..95bf812d6fc 100644
--- a/drivers/net/wireless/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -312,7 +312,7 @@ struct ar9170_rx_head {
u8 plcp[12];
} __packed;
-struct ar9170_rx_tail {
+struct ar9170_rx_phystatus {
union {
struct {
u8 rssi_ant0, rssi_ant1, rssi_ant2,
@@ -324,6 +324,9 @@ struct ar9170_rx_tail {
u8 evm_stream0[6], evm_stream1[6];
u8 phy_err;
+} __packed;
+
+struct ar9170_rx_macstatus {
u8 SAidx, DAidx;
u8 error;
u8 status;
@@ -339,7 +342,7 @@ struct ar9170_rx_tail {
#define AR9170_RX_ENC_SOFTWARE 0x8
-static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
+static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
{
return (t->SAidx & 0xc0) >> 4 |
(t->DAidx & 0xc0) >> 6;
@@ -357,10 +360,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
#define AR9170_RX_STATUS_MPDU_MASK 0x30
#define AR9170_RX_STATUS_MPDU_SINGLE 0x00
-#define AR9170_RX_STATUS_MPDU_FIRST 0x10
-#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20
-#define AR9170_RX_STATUS_MPDU_LAST 0x30
-
+#define AR9170_RX_STATUS_MPDU_FIRST 0x20
+#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30
+#define AR9170_RX_STATUS_MPDU_LAST 0x10
#define AR9170_RX_ERROR_RXTO 0x01
#define AR9170_RX_ERROR_OVERRUN 0x02
@@ -369,6 +371,7 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
#define AR9170_RX_ERROR_WRONG_RA 0x10
#define AR9170_RX_ERROR_PLCP 0x20
#define AR9170_RX_ERROR_MMIC 0x40
+#define AR9170_RX_ERROR_FATAL 0x80
struct ar9170_cmd_tx_status {
__le16 unkn;
diff --git a/drivers/net/wireless/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 341cead7f60..341cead7f60 100644
--- a/drivers/net/wireless/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
diff --git a/drivers/net/wireless/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index c8fa3073169..c8fa3073169 100644
--- a/drivers/net/wireless/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 5996ff9f7f4..1b60906b80c 100644
--- a/drivers/net/wireless/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -142,11 +142,36 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
};
#undef CHAN
+#define AR9170_HT_CAP \
+{ \
+ .ht_supported = true, \
+ .cap = IEEE80211_HT_CAP_MAX_AMSDU | \
+ IEEE80211_HT_CAP_SM_PS | \
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
+ IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_DSSSCCK40 | \
+ IEEE80211_HT_CAP_SM_PS, \
+ .ampdu_factor = 3, /* ?? */ \
+ .ampdu_density = 7, /* ?? */ \
+ .mcs = { \
+ .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ }, \
+}
+
static struct ieee80211_supported_band ar9170_band_2GHz = {
.channels = ar9170_2ghz_chantable,
.n_channels = ARRAY_SIZE(ar9170_2ghz_chantable),
.bitrates = ar9170_g_ratetable,
.n_bitrates = ar9170_g_ratetable_size,
+ .ht_cap = AR9170_HT_CAP,
+};
+
+static struct ieee80211_supported_band ar9170_band_5GHz = {
+ .channels = ar9170_5ghz_chantable,
+ .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable),
+ .bitrates = ar9170_a_ratetable,
+ .n_bitrates = ar9170_a_ratetable_size,
+ .ht_cap = AR9170_HT_CAP,
};
#ifdef AR9170_QUEUE_DEBUG
@@ -190,13 +215,6 @@ static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar,
}
#endif /* AR9170_QUEUE_DEBUG */
-static struct ieee80211_supported_band ar9170_band_5GHz = {
- .channels = ar9170_5ghz_chantable,
- .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable),
- .bitrates = ar9170_a_ratetable,
- .n_bitrates = ar9170_a_ratetable_size,
-};
-
void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
bool valid_status, u16 tx_status)
{
@@ -436,214 +454,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar,
}
}
-/*
- * If the frame alignment is right (or the kernel has
- * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
- * is only a single MPDU in the USB frame, then we can
- * submit to mac80211 the SKB directly. However, since
- * there may be multiple packets in one SKB in stream
- * mode, and we need to observe the proper ordering,
- * this is non-trivial.
- */
-static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
+static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
{
- struct sk_buff *skb;
- struct ar9170_rx_head *head = (void *)buf;
- struct ar9170_rx_tail *tail;
- struct ieee80211_rx_status status;
- int mpdu_len, i;
- u8 error, antennas = 0, decrypt;
- __le16 fc;
- int reserved;
+ memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head));
+ ar->rx_mpdu.has_plcp = false;
+}
- if (unlikely(!IS_STARTED(ar)))
- return ;
+static int ar9170_nag_limiter(struct ar9170 *ar)
+{
+ bool print_message;
+
+ /*
+ * we expect all sorts of errors in promiscuous mode.
+ * don't bother with it, it's OK!
+ */
+ if (ar->sniffer_enabled)
+ return false;
+
+ /*
+ * only go for frequent errors! The hardware tends to
+ * do some stupid thing once in a while under load, in
+ * noisy environments or just for fun!
+ */
+ if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit())
+ print_message = true;
+ else
+ print_message = false;
+
+ /* reset threshold for "once in a while" */
+ ar->bad_hw_nagger = jiffies + HZ / 4;
+ return print_message;
+}
+
+static int ar9170_rx_mac_status(struct ar9170 *ar,
+ struct ar9170_rx_head *head,
+ struct ar9170_rx_macstatus *mac,
+ struct ieee80211_rx_status *status)
+{
+ u8 error, decrypt;
- /* Received MPDU */
- mpdu_len = len;
- mpdu_len -= sizeof(struct ar9170_rx_head);
- mpdu_len -= sizeof(struct ar9170_rx_tail);
BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
- BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24);
+ BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
- if (mpdu_len <= FCS_LEN)
- return;
+ error = mac->error;
+ if (error & AR9170_RX_ERROR_MMIC) {
+ status->flag |= RX_FLAG_MMIC_ERROR;
+ error &= ~AR9170_RX_ERROR_MMIC;
+ }
- tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len);
+ if (error & AR9170_RX_ERROR_PLCP) {
+ status->flag |= RX_FLAG_FAILED_PLCP_CRC;
+ error &= ~AR9170_RX_ERROR_PLCP;
- for (i = 0; i < 3; i++)
- if (tail->rssi[i] != 0x80)
- antennas |= BIT(i);
+ if (!(ar->filter_state & FIF_PLCPFAIL))
+ return -EINVAL;
+ }
- /* post-process RSSI */
- for (i = 0; i < 7; i++)
- if (tail->rssi[i] & 0x80)
- tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f;
+ if (error & AR9170_RX_ERROR_FCS) {
+ status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ error &= ~AR9170_RX_ERROR_FCS;
- memset(&status, 0, sizeof(status));
+ if (!(ar->filter_state & FIF_FCSFAIL))
+ return -EINVAL;
+ }
+
+ decrypt = ar9170_get_decrypt_type(mac);
+ if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
+ decrypt != AR9170_ENC_ALG_NONE)
+ status->flag |= RX_FLAG_DECRYPTED;
- status.band = ar->channel->band;
- status.freq = ar->channel->center_freq;
- status.signal = ar->noise[0] + tail->rssi_combined;
- status.noise = ar->noise[0];
- status.antenna = antennas;
+ /* ignore wrong RA errors */
+ error &= ~AR9170_RX_ERROR_WRONG_RA;
+
+ if (error & AR9170_RX_ERROR_DECRYPT) {
+ error &= ~AR9170_RX_ERROR_DECRYPT;
+ /*
+ * Rx decryption is done in place,
+ * the original data is lost anyway.
+ */
+
+ return -EINVAL;
+ }
+
+ /* drop any other error frames */
+ if (unlikely(error)) {
+ /* TODO: update netdevice's RX dropped/errors statistics */
+
+ if (ar9170_nag_limiter(ar))
+ printk(KERN_DEBUG "%s: received frame with "
+ "suspicious error code (%#x).\n",
+ wiphy_name(ar->hw->wiphy), error);
+
+ return -EINVAL;
+ }
+
+ status->band = ar->channel->band;
+ status->freq = ar->channel->center_freq;
- switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) {
+ switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) {
case AR9170_RX_STATUS_MODULATION_CCK:
- if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
- status.flag |= RX_FLAG_SHORTPRE;
+ if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
+ status->flag |= RX_FLAG_SHORTPRE;
switch (head->plcp[0]) {
case 0x0a:
- status.rate_idx = 0;
+ status->rate_idx = 0;
break;
case 0x14:
- status.rate_idx = 1;
+ status->rate_idx = 1;
break;
case 0x37:
- status.rate_idx = 2;
+ status->rate_idx = 2;
break;
case 0x6e:
- status.rate_idx = 3;
+ status->rate_idx = 3;
break;
default:
- if ((!ar->sniffer_enabled) && (net_ratelimit()))
+ if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: invalid plcp cck rate "
"(%x).\n", wiphy_name(ar->hw->wiphy),
head->plcp[0]);
- return;
+ return -EINVAL;
}
break;
+
case AR9170_RX_STATUS_MODULATION_OFDM:
- switch (head->plcp[0] & 0xF) {
- case 0xB:
- status.rate_idx = 0;
+ switch (head->plcp[0] & 0xf) {
+ case 0xb:
+ status->rate_idx = 0;
break;
- case 0xF:
- status.rate_idx = 1;
+ case 0xf:
+ status->rate_idx = 1;
break;
- case 0xA:
- status.rate_idx = 2;
+ case 0xa:
+ status->rate_idx = 2;
break;
- case 0xE:
- status.rate_idx = 3;
+ case 0xe:
+ status->rate_idx = 3;
break;
case 0x9:
- status.rate_idx = 4;
+ status->rate_idx = 4;
break;
- case 0xD:
- status.rate_idx = 5;
+ case 0xd:
+ status->rate_idx = 5;
break;
case 0x8:
- status.rate_idx = 6;
+ status->rate_idx = 6;
break;
- case 0xC:
- status.rate_idx = 7;
+ case 0xc:
+ status->rate_idx = 7;
break;
default:
- if ((!ar->sniffer_enabled) && (net_ratelimit()))
+ if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: invalid plcp ofdm rate "
"(%x).\n", wiphy_name(ar->hw->wiphy),
head->plcp[0]);
- return;
+ return -EINVAL;
}
- if (status.band == IEEE80211_BAND_2GHZ)
- status.rate_idx += 4;
+ if (status->band == IEEE80211_BAND_2GHZ)
+ status->rate_idx += 4;
break;
+
case AR9170_RX_STATUS_MODULATION_HT:
+ if (head->plcp[3] & 0x80)
+ status->flag |= RX_FLAG_40MHZ;
+ if (head->plcp[6] & 0x80)
+ status->flag |= RX_FLAG_SHORT_GI;
+
+ status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f);
+ status->flag |= RX_FLAG_HT;
+ break;
+
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
/* XXX */
-
- if (net_ratelimit())
+ if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: invalid modulation\n",
wiphy_name(ar->hw->wiphy));
- return;
+ return -EINVAL;
}
- error = tail->error;
+ return 0;
+}
- if (error & AR9170_RX_ERROR_MMIC) {
- status.flag |= RX_FLAG_MMIC_ERROR;
- error &= ~AR9170_RX_ERROR_MMIC;
- }
+static void ar9170_rx_phy_status(struct ar9170 *ar,
+ struct ar9170_rx_phystatus *phy,
+ struct ieee80211_rx_status *status)
+{
+ int i;
- if (error & AR9170_RX_ERROR_PLCP) {
- status.flag |= RX_FLAG_FAILED_PLCP_CRC;
- error &= ~AR9170_RX_ERROR_PLCP;
+ BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
+
+ for (i = 0; i < 3; i++)
+ if (phy->rssi[i] != 0x80)
+ status->antenna |= BIT(i);
+
+ /* post-process RSSI */
+ for (i = 0; i < 7; i++)
+ if (phy->rssi[i] & 0x80)
+ phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
+
+ /* TODO: we could do something with phy_errors */
+ status->signal = ar->noise[0] + phy->rssi_combined;
+ status->noise = ar->noise[0];
+}
+
+static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
+{
+ struct sk_buff *skb;
+ int reserved = 0;
+ struct ieee80211_hdr *hdr = (void *) buf;
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ reserved += NET_IP_ALIGN;
+
+ if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ reserved += NET_IP_ALIGN;
}
- if (error & AR9170_RX_ERROR_FCS) {
- status.flag |= RX_FLAG_FAILED_FCS_CRC;
- error &= ~AR9170_RX_ERROR_FCS;
+ if (ieee80211_has_a4(hdr->frame_control))
+ reserved += NET_IP_ALIGN;
+
+ reserved = 32 + (reserved & NET_IP_ALIGN);
+
+ skb = dev_alloc_skb(len + reserved);
+ if (likely(skb)) {
+ skb_reserve(skb, reserved);
+ memcpy(skb_put(skb, len), buf, len);
}
- decrypt = ar9170_get_decrypt_type(tail);
- if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
- decrypt != AR9170_ENC_ALG_NONE)
- status.flag |= RX_FLAG_DECRYPTED;
+ return skb;
+}
- /* ignore wrong RA errors */
- error &= ~AR9170_RX_ERROR_WRONG_RA;
+/*
+ * If the frame alignment is right (or the kernel has
+ * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
+ * is only a single MPDU in the USB frame, then we could
+ * submit to mac80211 the SKB directly. However, since
+ * there may be multiple packets in one SKB in stream
+ * mode, and we need to observe the proper ordering,
+ * this is non-trivial.
+ */
- if (error & AR9170_RX_ERROR_DECRYPT) {
- error &= ~AR9170_RX_ERROR_DECRYPT;
+static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
+{
+ struct ar9170_rx_head *head;
+ struct ar9170_rx_macstatus *mac;
+ struct ar9170_rx_phystatus *phy = NULL;
+ struct ieee80211_rx_status status;
+ struct sk_buff *skb;
+ int mpdu_len;
+
+ if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac))))
+ return ;
+
+ /* Received MPDU */
+ mpdu_len = len - sizeof(*mac);
+
+ mac = (void *)(buf + mpdu_len);
+ if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
+ /* this frame is too damaged and can't be used - drop it */
- /*
- * Rx decryption is done in place,
- * the original data is lost anyway.
- */
return ;
}
- /* drop any other error frames */
- if ((error) && (net_ratelimit())) {
- printk(KERN_DEBUG "%s: errors: %#x\n",
- wiphy_name(ar->hw->wiphy), error);
- return;
+ switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) {
+ case AR9170_RX_STATUS_MPDU_FIRST:
+ /* first mpdu packet has the plcp header */
+ if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
+ head = (void *) buf;
+ memcpy(&ar->rx_mpdu.plcp, (void *) buf,
+ sizeof(struct ar9170_rx_head));
+
+ mpdu_len -= sizeof(struct ar9170_rx_head);
+ buf += sizeof(struct ar9170_rx_head);
+ ar->rx_mpdu.has_plcp = true;
+ } else {
+ if (ar9170_nag_limiter(ar))
+ printk(KERN_ERR "%s: plcp info is clipped.\n",
+ wiphy_name(ar->hw->wiphy));
+ return ;
+ }
+ break;
+
+ case AR9170_RX_STATUS_MPDU_LAST:
+ /* last mpdu has a extra tail with phy status information */
+
+ if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
+ mpdu_len -= sizeof(struct ar9170_rx_phystatus);
+ phy = (void *)(buf + mpdu_len);
+ } else {
+ if (ar9170_nag_limiter(ar))
+ printk(KERN_ERR "%s: frame tail is clipped.\n",
+ wiphy_name(ar->hw->wiphy));
+ return ;
+ }
+
+ case AR9170_RX_STATUS_MPDU_MIDDLE:
+ /* middle mpdus are just data */
+ if (unlikely(!ar->rx_mpdu.has_plcp)) {
+ if (!ar9170_nag_limiter(ar))
+ return ;
+
+ printk(KERN_ERR "%s: rx stream did not start "
+ "with a first_mpdu frame tag.\n",
+ wiphy_name(ar->hw->wiphy));
+
+ return ;
+ }
+
+ head = &ar->rx_mpdu.plcp;
+ break;
+
+ case AR9170_RX_STATUS_MPDU_SINGLE:
+ /* single mpdu - has plcp (head) and phy status (tail) */
+ head = (void *) buf;
+
+ mpdu_len -= sizeof(struct ar9170_rx_head);
+ mpdu_len -= sizeof(struct ar9170_rx_phystatus);
+
+ buf += sizeof(struct ar9170_rx_head);
+ phy = (void *)(buf + mpdu_len);
+ break;
+
+ default:
+ BUG_ON(1);
+ break;
}
- buf += sizeof(struct ar9170_rx_head);
- fc = *(__le16 *)buf;
+ if (unlikely(mpdu_len < FCS_LEN))
+ return ;
- if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc))
- reserved = 32 + 2;
- else
- reserved = 32;
+ memset(&status, 0, sizeof(status));
+ if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status)))
+ return ;
- skb = dev_alloc_skb(mpdu_len + reserved);
- if (!skb)
- return;
+ if (phy)
+ ar9170_rx_phy_status(ar, phy, &status);
- skb_reserve(skb, reserved);
- memcpy(skb_put(skb, mpdu_len), buf, mpdu_len);
- ieee80211_rx_irqsafe(ar->hw, skb, &status);
+ skb = ar9170_rx_copy_data(buf, mpdu_len);
+ if (likely(skb))
+ ieee80211_rx_irqsafe(ar->hw, skb, &status);
}
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
{
- unsigned int i, tlen, resplen;
+ unsigned int i, tlen, resplen, wlen = 0, clen = 0;
u8 *tbuf, *respbuf;
tbuf = skb->data;
tlen = skb->len;
while (tlen >= 4) {
- int clen = tbuf[1] << 8 | tbuf[0];
- int wlen = (clen + 3) & ~3;
+ clen = tbuf[1] << 8 | tbuf[0];
+ wlen = ALIGN(clen, 4);
- /*
- * parse stream (if any)
- */
+ /* check if this is stream has a valid tag.*/
if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
- printk(KERN_ERR "%s: missing tag!\n",
- wiphy_name(ar->hw->wiphy));
+ /*
+ * TODO: handle the highly unlikely event that the
+ * corrupted stream has the TAG at the right position.
+ */
+
+ /* check if the frame can be repaired. */
+ if (!ar->rx_failover_missing) {
+ /* this is no "short read". */
+ if (ar9170_nag_limiter(ar)) {
+ printk(KERN_ERR "%s: missing tag!\n",
+ wiphy_name(ar->hw->wiphy));
+ goto err_telluser;
+ } else
+ goto err_silent;
+ }
+
+ if (ar->rx_failover_missing > tlen) {
+ if (ar9170_nag_limiter(ar)) {
+ printk(KERN_ERR "%s: possible multi "
+ "stream corruption!\n",
+ wiphy_name(ar->hw->wiphy));
+ goto err_telluser;
+ } else
+ goto err_silent;
+ }
+
+ memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
+ ar->rx_failover_missing -= tlen;
+
+ if (ar->rx_failover_missing <= 0) {
+ /*
+ * nested ar9170_rx call!
+ * termination is guranteed, even when the
+ * combined frame also have a element with
+ * a bad tag.
+ */
+
+ ar->rx_failover_missing = 0;
+ ar9170_rx(ar, ar->rx_failover);
+
+ skb_reset_tail_pointer(ar->rx_failover);
+ skb_trim(ar->rx_failover, 0);
+ }
+
return ;
}
+
+ /* check if stream is clipped */
if (wlen > tlen - 4) {
- printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n",
- wiphy_name(ar->hw->wiphy), clen, wlen, tlen);
- print_hex_dump(KERN_DEBUG, "data: ",
- DUMP_PREFIX_OFFSET,
- 16, 1, tbuf, tlen, true);
+ if (ar->rx_failover_missing) {
+ /* TODO: handle double stream corruption. */
+ if (ar9170_nag_limiter(ar)) {
+ printk(KERN_ERR "%s: double rx stream "
+ "corruption!\n",
+ wiphy_name(ar->hw->wiphy));
+ goto err_telluser;
+ } else
+ goto err_silent;
+ }
+
+ /*
+ * save incomplete data set.
+ * the firmware will resend the missing bits when
+ * the rx - descriptor comes round again.
+ */
+
+ memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
+ ar->rx_failover_missing = clen - tlen;
return ;
}
resplen = clen;
@@ -668,12 +902,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (i == 12)
ar9170_handle_command_response(ar, respbuf, resplen);
else
- ar9170_handle_mpdu(ar, respbuf, resplen);
+ ar9170_handle_mpdu(ar, respbuf, clen);
}
- if (tlen)
- printk(KERN_ERR "%s: buffer remains!\n",
- wiphy_name(ar->hw->wiphy));
+ if (tlen) {
+ if (net_ratelimit())
+ printk(KERN_ERR "%s: %d bytes of unprocessed "
+ "data left in rx stream!\n",
+ wiphy_name(ar->hw->wiphy), tlen);
+
+ goto err_telluser;
+ }
+
+ return ;
+
+err_telluser:
+ printk(KERN_ERR "%s: damaged RX stream data [want:%d, "
+ "data:%d, rx:%d, pending:%d ]\n",
+ wiphy_name(ar->hw->wiphy), clen, wlen, tlen,
+ ar->rx_failover_missing);
+
+ if (ar->rx_failover_missing)
+ print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
+ ar->rx_failover->data,
+ ar->rx_failover->len);
+
+ print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
+ skb->data, skb->len);
+
+ printk(KERN_ERR "%s: please check your hardware and cables, if "
+ "you see this message frequently.\n",
+ wiphy_name(ar->hw->wiphy));
+
+err_silent:
+ if (ar->rx_failover_missing) {
+ skb_reset_tail_pointer(ar->rx_failover);
+ skb_trim(ar->rx_failover, 0);
+ ar->rx_failover_missing = 0;
+ }
}
#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \
@@ -703,6 +969,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ ar->bad_hw_nagger = jiffies;
+
err = ar->open(ar);
if (err)
goto out;
@@ -742,8 +1010,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
if (IS_STARTED(ar))
ar->state = AR9170_IDLE;
- mutex_lock(&ar->mutex);
+ flush_workqueue(ar->hw->workqueue);
+ mutex_lock(&ar->mutex);
cancel_delayed_work_sync(&ar->tx_status_janitor);
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
@@ -1076,7 +1345,8 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
err = ar9170_set_channel(ar, hw->conf.channel,
- AR9170_RFI_NONE, AR9170_BW_20);
+ AR9170_RFI_NONE,
+ nl80211_to_ar9170(hw->conf.channel_type));
if (err)
goto out;
/* adjust slot time for 5 GHz */
@@ -1123,10 +1393,10 @@ static void ar9170_set_filters(struct work_struct *work)
filter_config_work);
int err;
- mutex_lock(&ar->mutex);
if (unlikely(!IS_STARTED(ar)))
- goto unlock;
+ return ;
+ mutex_lock(&ar->mutex);
if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) {
err = ar9170_set_operating_mode(ar);
if (err)
@@ -1155,8 +1425,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
/* mask supported flags */
*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
- FIF_PROMISC_IN_BSS;
-
+ FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
+ ar->filter_state = *new_flags;
/*
* We can support more by setting the sniffer bit and
* then checking the error flags, later.
@@ -1498,6 +1768,24 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
return ret;
}
+static int ar9170_ampdu_action(struct ieee80211_hw *hw,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ /*
+ * Something goes wrong -- RX locks up
+ * after a while of receiving aggregated
+ * frames -- not enabling for now.
+ */
+ return -EOPNOTSUPP;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct ieee80211_ops ar9170_ops = {
.start = ar9170_op_start,
.stop = ar9170_op_stop,
@@ -1514,26 +1802,40 @@ static const struct ieee80211_ops ar9170_ops = {
.sta_notify = ar9170_sta_notify,
.get_stats = ar9170_get_stats,
.get_tx_stats = ar9170_get_tx_stats,
+ .ampdu_action = ar9170_ampdu_action,
};
void *ar9170_alloc(size_t priv_size)
{
struct ieee80211_hw *hw;
struct ar9170 *ar;
+ struct sk_buff *skb;
int i;
+ /*
+ * this buffer is used for rx stream reconstruction.
+ * Under heavy load this device (or the transport layer?)
+ * tends to split the streams into seperate rx descriptors.
+ */
+
+ skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
+ if (!skb)
+ goto err_nomem;
+
hw = ieee80211_alloc_hw(priv_size, &ar9170_ops);
if (!hw)
- return ERR_PTR(-ENOMEM);
+ goto err_nomem;
ar = hw->priv;
ar->hw = hw;
+ ar->rx_failover = skb;
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
skb_queue_head_init(&ar->global_tx_status);
skb_queue_head_init(&ar->global_tx_status_waste);
+ ar9170_rx_reset_rx_mpdu(ar);
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor);
@@ -1561,6 +1863,10 @@ void *ar9170_alloc(size_t priv_size)
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
return ar;
+
+err_nomem:
+ kfree_skb(skb);
+ return ERR_PTR(-ENOMEM);
}
static int ar9170_read_eeprom(struct ar9170 *ar)
@@ -1619,12 +1925,24 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
else
ar->hw->channel_change_time = 80 * 1000;
+ ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
+ ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
+
/* second part of wiphy init */
SET_IEEE80211_PERM_ADDR(ar->hw, addr);
return bands ? 0 : -EINVAL;
}
+static int ar9170_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ar9170 *ar = hw->priv;
+
+ return ath_reg_notifier_apply(wiphy, request, &ar->regulatory);
+}
+
int ar9170_register(struct ar9170 *ar, struct device *pdev)
{
int err;
@@ -1634,10 +1952,18 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
if (err)
goto err_out;
+ err = ath_regd_init(&ar->regulatory, ar->hw->wiphy,
+ ar9170_reg_notifier);
+ if (err)
+ goto err_out;
+
err = ieee80211_register_hw(ar->hw);
if (err)
goto err_out;
+ if (!ath_is_world_regd(&ar->regulatory))
+ regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2);
+
err = ar9170_init_leds(ar);
if (err)
goto err_unreg;
@@ -1666,6 +1992,7 @@ void ar9170_unregister(struct ar9170 *ar)
ar9170_unregister_leds(ar);
#endif /* CONFIG_AR9170_LEDS */
+ kfree_skb(ar->rx_failover);
ieee80211_unregister_hw(ar->hw);
mutex_destroy(&ar->mutex);
}
diff --git a/drivers/net/wireless/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index 6ce20754b8e..6ce20754b8e 100644
--- a/drivers/net/wireless/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index fddda477095..fddda477095 100644
--- a/drivers/net/wireless/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
diff --git a/drivers/net/wireless/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index f5852924cd6..ac42586495d 100644
--- a/drivers/net/wireless/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -43,7 +43,7 @@
#include <linux/completion.h>
#include <linux/spinlock.h>
#include <linux/leds.h>
-#include <net/wireless.h>
+#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/firmware.h>
#include "eeprom.h"
diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index 75383a5df99..509b6f94f73 100644
--- a/drivers/net/wireless/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,6 +1,7 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ select ATH_COMMON
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index 84a74c5248e..84a74c5248e 100644
--- a/drivers/net/wireless/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 0b616e72fe0..60c6d2edc4b 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -27,6 +27,8 @@
#include <linux/types.h>
#include <net/mac80211.h>
+#include "../regd.h"
+
/* RX/TX descriptor hw structs
* TODO: Driver part should only see sw structs */
#include "desc.h"
@@ -1039,8 +1041,6 @@ struct ath5k_hw {
bool ah_5ghz;
bool ah_2ghz;
-#define ah_regdomain ah_capabilities.cap_regdomain.reg_current
-#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
@@ -1065,6 +1065,7 @@ struct ath5k_hw {
u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
+ struct ath_regulatory ah_regulatory;
struct ath5k_capabilities ah_capabilities;
struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES];
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 70d376c63aa..70d376c63aa 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index a08bc8a4fb6..c8c658bfcf9 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -61,9 +61,13 @@
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_all_channels;
+module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
+MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
+
/******************\
* Internal defines *
@@ -705,6 +709,15 @@ err_no_irq:
* Driver Initialization *
\***********************/
+static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ath5k_softc *sc = hw->priv;
+ struct ath_regulatory *reg = &sc->ah->ah_regulatory;
+
+ return ath_reg_notifier_apply(wiphy, request, reg);
+}
+
static int
ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
{
@@ -793,12 +806,23 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
memset(sc->bssidmask, 0xff, ETH_ALEN);
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+ ah->ah_regulatory.current_rd =
+ ah->ah_capabilities.cap_eeprom.ee_regdomain;
+ ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier);
+ if (ret) {
+ ATH5K_ERR(sc, "can't initialize regulatory system\n");
+ goto err_queues;
+ }
+
ret = ieee80211_register_hw(hw);
if (ret) {
ATH5K_ERR(sc, "can't register ieee80211 hw\n");
goto err_queues;
}
+ if (!ath_is_world_regd(&sc->ah->ah_regulatory))
+ regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2);
+
ath5k_init_leds(sc);
return 0;
@@ -862,6 +886,20 @@ ath5k_ieee2mhz(short chan)
return 2212 + chan * 20;
}
+/*
+ * Returns true for the channel numbers used without all_channels modparam.
+ */
+static bool ath5k_is_standard_channel(short chan)
+{
+ return ((chan <= 14) ||
+ /* UNII 1,2 */
+ ((chan & 3) == 0 && chan >= 36 && chan <= 64) ||
+ /* midband */
+ ((chan & 3) == 0 && chan >= 100 && chan <= 140) ||
+ /* UNII-3 */
+ ((chan & 3) == 1 && chan >= 149 && chan <= 165));
+}
+
static unsigned int
ath5k_copy_channels(struct ath5k_hw *ah,
struct ieee80211_channel *channels,
@@ -899,6 +937,9 @@ ath5k_copy_channels(struct ath5k_hw *ah,
if (!ath5k_channel_ok(ah, freq, chfreq))
continue;
+ if (!modparam_all_channels && !ath5k_is_standard_channel(ch))
+ continue;
+
/* Write channel info and increment counter */
channels[count].center_freq = freq;
channels[count].band = (chfreq == CHANNEL_2GHZ) ?
@@ -1577,9 +1618,8 @@ ath5k_rx_start(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
sc->cachelsz, sc->rxbufsize);
- sc->rxlink = NULL;
-
spin_lock_bh(&sc->rxbuflock);
+ sc->rxlink = NULL;
list_for_each_entry(bf, &sc->rxbuf, list) {
ret = ath5k_rxbuf_setup(sc, bf);
if (ret != 0) {
@@ -1588,9 +1628,9 @@ ath5k_rx_start(struct ath5k_softc *sc)
}
}
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+ ath5k_hw_set_rxdp(ah, bf->daddr);
spin_unlock_bh(&sc->rxbuflock);
- ath5k_hw_set_rxdp(ah, bf->daddr);
ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */
ath5k_mode_setup(sc); /* set filters, etc. */
ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
@@ -1739,7 +1779,7 @@ ath5k_tasklet_rx(unsigned long data)
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
struct ath5k_softc *sc = (void *)data;
- struct ath5k_buf *bf, *bf_last;
+ struct ath5k_buf *bf;
struct ath5k_desc *ds;
int ret;
int hdrlen;
@@ -1750,7 +1790,6 @@ ath5k_tasklet_rx(unsigned long data)
ATH5K_WARN(sc, "empty rx buf pool\n");
goto unlock;
}
- bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
do {
rxs.flag = 0;
@@ -1759,24 +1798,9 @@ ath5k_tasklet_rx(unsigned long data)
skb = bf->skb;
ds = bf->desc;
- /*
- * last buffer must not be freed to ensure proper hardware
- * function. When the hardware finishes also a packet next to
- * it, we are sure, it doesn't use it anymore and we can go on.
- */
- if (bf_last == bf)
- bf->flags |= 1;
- if (bf->flags) {
- struct ath5k_buf *bf_next = list_entry(bf->list.next,
- struct ath5k_buf, list);
- ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
- &rs);
- if (ret)
- break;
- bf->flags &= ~1;
- /* skip the overwritten one (even status is martian) */
- goto next;
- }
+ /* bail if HW is still using self-linked descriptor */
+ if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr)
+ break;
ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
if (unlikely(ret == -EINPROGRESS))
@@ -2455,7 +2479,7 @@ ath5k_intr(int irq, void *dev_id)
tasklet_schedule(&sc->restq);
} else {
if (status & AR5K_INT_SWBA) {
- tasklet_schedule(&sc->beacontq);
+ tasklet_hi_schedule(&sc->beacontq);
}
if (status & AR5K_INT_RXEOL) {
/*
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 822956114cd..852b2c189fd 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -56,7 +56,6 @@
struct ath5k_buf {
struct list_head list;
- unsigned int flags; /* rx descriptor flags */
struct ath5k_desc *desc; /* virtual addr of desc */
dma_addr_t daddr; /* physical addr of desc */
struct sk_buff *skb; /* skbuff for buf */
diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index 367a6c7d3cc..367a6c7d3cc 100644
--- a/drivers/net/wireless/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 9770bb3d40f..9770bb3d40f 100644
--- a/drivers/net/wireless/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index 66f69f04e55..66f69f04e55 100644
--- a/drivers/net/wireless/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index dc30a2b70a6..dc30a2b70a6 100644
--- a/drivers/net/wireless/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
diff --git a/drivers/net/wireless/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h
index 56158c804e3..56158c804e3 100644
--- a/drivers/net/wireless/ath5k/desc.h
+++ b/drivers/net/wireless/ath/ath5k/desc.h
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index b65b4feb2d2..941b51130a6 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -80,8 +80,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
* ath5k_hw_get_rxdp - Get RX Descriptor's address
*
* @ah: The &struct ath5k_hw
- *
- * XXX: Is RXDP read and clear ?
*/
u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
{
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index c0fb3b09ba4..c0fb3b09ba4 100644
--- a/drivers/net/wireless/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h
index b0c0606dea0..b0c0606dea0 100644
--- a/drivers/net/wireless/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath/ath5k/eeprom.h
diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e73d02..64a27e73d02 100644
--- a/drivers/net/wireless/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 61fb621ed20..18eb5190ce4 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -537,8 +537,6 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
{ AR5K_DCU_TX_FILTER_1(15), 0x00000000 },
{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
{ AR5K_DCU_TX_FILTER_SET, 0x00000000 },
- { AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
- { AR5K_DCU_TX_FILTER_SET, 0x00000000 },
{ AR5K_STA_ID1, 0x00000000 },
{ AR5K_BSS_ID0, 0x00000000 },
{ AR5K_BSS_ID1, 0x00000000 },
@@ -669,7 +667,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
/*{ AR5K_PHY(650), 0x000001b5 },*/
{ AR5K_PHY(651), 0x00000000 },
{ AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
- { AR5K_PHY_TXPOWER_RATE2, 0x20202020 },
+ { AR5K_PHY_TXPOWER_RATE4, 0x20202020 },
/*{ AR5K_PHY(655), 0x13c889af },*/
{ AR5K_PHY(656), 0x38490a20 },
{ AR5K_PHY(657), 0x00007bb6 },
@@ -718,7 +716,7 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
{ AR5K_PHY_SETTLING,
{ 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
{ AR5K_PHY_AGCCTL,
- { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
+ { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
{ AR5K_PHY_NF,
{ 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
@@ -799,7 +797,7 @@ static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
{ AR5K_PHY_DESIRED_SIZE,
{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
{ AR5K_PHY_SIG,
- { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
+ { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
{ AR5K_PHY_AGCCOARSE,
{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
diff --git a/drivers/net/wireless/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 19555fb79c9..cbdc0b30842 100644
--- a/drivers/net/wireless/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -67,6 +67,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
{ ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) },
/* Acer Extensa 5620z (nekoreeve@gmail.com) */
{ ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) },
+ /* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */
+ { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
{ }
};
@@ -78,7 +80,7 @@ void ath5k_led_enable(struct ath5k_softc *sc)
}
}
-void ath5k_led_on(struct ath5k_softc *sc)
+static void ath5k_led_on(struct ath5k_softc *sc)
{
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
return;
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 55122f1e198..55122f1e198 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 9e2faae5ae9..b48b29dca3d 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1487,28 +1487,35 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
{
s8 tmp;
s16 min_pwrL, min_pwrR;
- s16 pwr_i = pwrL[0];
-
- do {
- pwr_i--;
- tmp = (s8) ath5k_get_interpolated_value(pwr_i,
- pwrL[0], pwrL[1],
- stepL[0], stepL[1]);
-
- } while (tmp > 1);
-
- min_pwrL = pwr_i;
-
- pwr_i = pwrR[0];
- do {
- pwr_i--;
- tmp = (s8) ath5k_get_interpolated_value(pwr_i,
- pwrR[0], pwrR[1],
- stepR[0], stepR[1]);
-
- } while (tmp > 1);
+ s16 pwr_i;
+
+ if (pwrL[0] == pwrL[1])
+ min_pwrL = pwrL[0];
+ else {
+ pwr_i = pwrL[0];
+ do {
+ pwr_i--;
+ tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+ pwrL[0], pwrL[1],
+ stepL[0], stepL[1]);
+ } while (tmp > 1);
+
+ min_pwrL = pwr_i;
+ }
- min_pwrR = pwr_i;
+ if (pwrR[0] == pwrR[1])
+ min_pwrR = pwrR[0];
+ else {
+ pwr_i = pwrR[0];
+ do {
+ pwr_i--;
+ tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+ pwrR[0], pwrR[1],
+ stepR[0], stepR[1]);
+ } while (tmp > 1);
+
+ min_pwrR = pwr_i;
+ }
/* Keep the right boundary so that it works for both curves */
return max(min_pwrL, min_pwrR);
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 5094c394a4b..5094c394a4b 100644
--- a/drivers/net/wireless/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 7070d1543cd..7070d1543cd 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index cb5e15f9709..775fdf78554 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -358,7 +358,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode |= AR5K_PHY_MODE_FREQ_5GHZ;
if (ah->ah_radio == AR5K_RF5413)
- clock |= AR5K_PHY_PLL_40MHZ_5413;
+ clock = AR5K_PHY_PLL_40MHZ_5413;
else
clock |= AR5K_PHY_PLL_40MHZ;
diff --git a/drivers/net/wireless/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h
index e50baff6617..e50baff6617 100644
--- a/drivers/net/wireless/ath5k/rfbuffer.h
+++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h
diff --git a/drivers/net/wireless/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h
index 1354d8c392c..1354d8c392c 100644
--- a/drivers/net/wireless/ath5k/rfgain.h
+++ b/drivers/net/wireless/ath/ath5k/rfgain.h
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 90a8dd87378..0ed1ac312aa 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -2,6 +2,7 @@ config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
depends on RFKILL || RFKILL=n
+ select ATH_COMMON
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 1a4d4eab6fe..783bc39eb2f 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -4,7 +4,6 @@ ath9k-y += hw.o \
calib.o \
ani.o \
phy.o \
- regd.o \
beacon.o \
main.o \
recv.o \
diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 0e65c51ba17..0e65c51ba17 100644
--- a/drivers/net/wireless/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 6c5e887d50d..1aeafb511dd 100644
--- a/drivers/net/wireless/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -569,8 +569,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
"phyCnt1 0x%x, resetting "
"counter value to 0x%x\n",
- phyCnt1,
- aniState->ofdmPhyErrBase);
+ phyCnt1, aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_1,
aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
@@ -580,8 +579,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
"phyCnt2 0x%x, resetting "
"counter value to 0x%x\n",
- phyCnt2,
- aniState->cckPhyErrBase);
+ phyCnt2, aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2,
aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
@@ -667,7 +665,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 cc = REG_READ(ah, AR_CCCNT);
if (cycles == 0 || cycles > cc) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
"cycle counter wrap. ExtBusy = 0\n");
good = 0;
} else {
diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 08b4e7ed5ff..08b4e7ed5ff 100644
--- a/drivers/net/wireless/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7b1b40aaf09..c92d46fa9d5 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -66,7 +66,6 @@ struct ath_config {
u32 ath_aggr_prot;
u16 txpowlimit;
u8 cabqReadytime;
- u8 swBeaconProcess;
};
/*************************/
@@ -74,13 +73,17 @@ struct ath_config {
/*************************/
#define ATH_TXBUF_RESET(_bf) do { \
- (_bf)->bf_status = 0; \
+ (_bf)->bf_stale = false; \
(_bf)->bf_lastbf = NULL; \
(_bf)->bf_next = NULL; \
memset(&((_bf)->bf_state), 0, \
sizeof(struct ath_buf_state)); \
} while (0)
+#define ATH_RXBUF_RESET(_bf) do { \
+ (_bf)->bf_stale = false; \
+ } while (0)
+
/**
* enum buffer_type - Buffer type flags
*
@@ -106,7 +109,7 @@ struct ath_buf_state {
int bfs_seqno;
int bfs_tidno;
int bfs_retries;
- u32 bf_type;
+ u8 bf_type;
u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
@@ -130,26 +133,21 @@ struct ath_buf {
struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
an aggregate) */
struct ath_buf *bf_next; /* next subframe in the aggregate */
- void *bf_mpdu; /* enclosing frame structure */
+ struct sk_buff *bf_mpdu; /* enclosing frame structure */
struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
- u32 bf_status;
+ bool bf_stale;
u16 bf_flags;
struct ath_buf_state bf_state;
dma_addr_t bf_dmacontext;
};
-#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0)
-#define ATH_BUFSTATUS_STALE 0x00000002
-
struct ath_descdma {
- const char *dd_name;
struct ath_desc *dd_desc;
dma_addr_t dd_desc_paddr;
u32 dd_desc_len;
struct ath_buf *dd_bufptr;
- dma_addr_t dd_dmacontext;
};
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
@@ -295,26 +293,6 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
-/* All RSSI values are noise floor adjusted */
-struct ath_tx_stat {
- int rssi;
- int rssictl[ATH_MAX_ANTENNA];
- int rssiextn[ATH_MAX_ANTENNA];
- int rateieee;
- int rateKbps;
- int ratecode;
- int flags;
- u32 airtime; /* time on air per final tx rate */
-};
-
-struct aggr_rifs_param {
- int param_max_frames;
- int param_max_len;
- int param_rl;
- int param_al;
- struct ath_rc_series *param_rcs;
-};
-
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
@@ -362,7 +340,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
-int ath_tx_cleanup(struct ath_softc *sc);
+void ath_tx_cleanup(struct ath_softc *sc);
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
@@ -525,19 +503,18 @@ struct ath_rfkill {
#define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2)
#define SC_OP_TXAGGR BIT(3)
-#define SC_OP_CHAINMASK_UPDATE BIT(4)
-#define SC_OP_FULL_RESET BIT(5)
-#define SC_OP_PREAMBLE_SHORT BIT(6)
-#define SC_OP_PROTECT_ENABLE BIT(7)
-#define SC_OP_RXFLUSH BIT(8)
-#define SC_OP_LED_ASSOCIATED BIT(9)
-#define SC_OP_RFKILL_REGISTERED BIT(10)
-#define SC_OP_RFKILL_SW_BLOCKED BIT(11)
-#define SC_OP_RFKILL_HW_BLOCKED BIT(12)
-#define SC_OP_WAIT_FOR_BEACON BIT(13)
-#define SC_OP_LED_ON BIT(14)
-#define SC_OP_SCANNING BIT(15)
-#define SC_OP_TSF_RESET BIT(16)
+#define SC_OP_FULL_RESET BIT(4)
+#define SC_OP_PREAMBLE_SHORT BIT(5)
+#define SC_OP_PROTECT_ENABLE BIT(6)
+#define SC_OP_RXFLUSH BIT(7)
+#define SC_OP_LED_ASSOCIATED BIT(8)
+#define SC_OP_RFKILL_REGISTERED BIT(9)
+#define SC_OP_RFKILL_SW_BLOCKED BIT(10)
+#define SC_OP_RFKILL_HW_BLOCKED BIT(11)
+#define SC_OP_WAIT_FOR_BEACON BIT(12)
+#define SC_OP_LED_ON BIT(13)
+#define SC_OP_SCANNING BIT(14)
+#define SC_OP_TSF_RESET BIT(15)
struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index ec995730632..eb4759fc6a0 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -43,7 +43,7 @@ static int ath_beaconq_config(struct ath_softc *sc)
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "unable to update h/w beacon queue parameters\n");
+ "Unable to update h/w beacon queue parameters\n");
return 0;
} else {
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
@@ -59,7 +59,7 @@ static int ath_beaconq_config(struct ath_softc *sc)
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct ath_buf *bf)
{
- struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
@@ -132,16 +132,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
avp = (void *)vif->drv_priv;
cabq = sc->beacon.cabq;
- if (avp->av_bcbuf == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
- avp, avp->av_bcbuf);
+ if (avp->av_bcbuf == NULL)
return NULL;
- }
/* Release the old beacon first */
bf = avp->av_bcbuf;
- skb = (struct sk_buff *)bf->bf_mpdu;
+ skb = bf->bf_mpdu;
if (skb) {
dma_unmap_single(sc->dev, bf->bf_dmacontext,
skb->len, DMA_TO_DEVICE);
@@ -229,7 +226,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
return;
bf = avp->av_bcbuf;
- skb = (struct sk_buff *) bf->bf_mpdu;
+ skb = bf->bf_mpdu;
ath_beacon_setup(sc, avp, bf);
@@ -302,7 +299,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
/* release the previous beacon frame, if it already exists. */
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
- skb = (struct sk_buff *)bf->bf_mpdu;
+ skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_dmacontext,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
@@ -374,7 +371,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
- struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_dmacontext,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index e2d62e97131..a197041d76b 100644
--- a/drivers/net/wireless/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -186,7 +186,7 @@ static bool getNoiseFloorThresh(struct ath_hw *ah,
}
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
- struct hal_cal_list *currCal)
+ struct ath9k_cal_list *currCal)
{
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
@@ -220,7 +220,7 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah,
}
static void ath9k_hw_reset_calibration(struct ath_hw *ah,
- struct hal_cal_list *currCal)
+ struct ath9k_cal_list *currCal)
{
int i;
@@ -238,13 +238,12 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah,
ah->cal_samples = 0;
}
-static void ath9k_hw_per_calibration(struct ath_hw *ah,
+static bool ath9k_hw_per_calibration(struct ath_hw *ah,
struct ath9k_channel *ichan,
u8 rxchainmask,
- struct hal_cal_list *currCal,
- bool *isCalDone)
+ struct ath9k_cal_list *currCal)
{
- *isCalDone = false;
+ bool iscaldone = false;
if (currCal->calState == CAL_RUNNING) {
if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
@@ -263,7 +262,7 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah,
currCal->calData->calPostProc(ah, numChains);
ichan->CalValid |= currCal->calData->calType;
currCal->calState = CAL_DONE;
- *isCalDone = true;
+ iscaldone = true;
} else {
ath9k_hw_setup_calibration(ah, currCal);
}
@@ -271,11 +270,13 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah,
} else if (!(ichan->CalValid & currCal->calData->calType)) {
ath9k_hw_reset_calibration(ah, currCal);
}
+
+ return iscaldone;
}
/* Assumes you are talking about the currently configured channel */
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
- enum hal_cal_types calType)
+ enum ath9k_cal_types calType)
{
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
@@ -284,8 +285,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
return true;
case ADC_GAIN_CAL:
case ADC_DC_CAL:
- if (conf->channel->band == IEEE80211_BAND_5GHZ &&
- conf_is_ht20(conf))
+ if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
+ conf_is_ht20(conf)))
return true;
break;
}
@@ -498,7 +499,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
{
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
- const struct hal_percal_data *calData =
+ const struct ath9k_percal_data *calData =
ah->cal_list_curr->calData;
u32 numSamples =
(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
@@ -555,7 +556,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
- struct hal_cal_list *currCal = ah->cal_list_curr;
+ struct ath9k_cal_list *currCal = ah->cal_list_curr;
if (!ah->curchan)
return true;
@@ -841,23 +842,21 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
}
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
- u8 rxchainmask, bool longcal,
- bool *isCalDone)
+ u8 rxchainmask, bool longcal)
{
- struct hal_cal_list *currCal = ah->cal_list_curr;
-
- *isCalDone = true;
+ bool iscaldone = true;
+ struct ath9k_cal_list *currCal = ah->cal_list_curr;
if (currCal &&
(currCal->calState == CAL_RUNNING ||
currCal->calState == CAL_WAITING)) {
- ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
- isCalDone);
- if (*isCalDone) {
+ iscaldone = ath9k_hw_per_calibration(ah, chan,
+ rxchainmask, currCal);
+ if (iscaldone) {
ah->cal_list_curr = currCal = currCal->calNext;
if (currCal->calState == CAL_WAITING) {
- *isCalDone = false;
+ iscaldone = false;
ath9k_hw_reset_calibration(ah, currCal);
}
}
@@ -872,18 +871,15 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_getnf(ah, chan);
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah);
-
- if (chan->channelFlags & CHANNEL_CW_INT)
- chan->channelFlags &= ~CHANNEL_CW_INT;
}
- return true;
+ return iscaldone;
}
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
{
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
- if (chan->channelFlags & CHANNEL_HT20) {
+ if (IS_CHAN_HT20(chan)) {
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
@@ -919,83 +915,66 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
return true;
}
-bool ath9k_hw_init_cal(struct ath_hw *ah,
- struct ath9k_channel *chan)
+bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
{
if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
if (!ar9285_clc(ah, chan))
return false;
- } else if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
- REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+ } else {
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ }
- /* Kick off the cal */
+ /* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_CAL);
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_CAL);
- if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_CAL, 0,
- AH_WAIT_TIMEOUT)) {
+ /* Poll for offset calibration complete */
+ if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+ 0, AH_WAIT_TIMEOUT)) {
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
"offset calibration failed to complete in 1ms; "
"noisy environment?\n");
return false;
}
- REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
- REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
- }
-
- /* Calibrate the AGC */
- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_CAL);
-
- if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
- 0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "offset calibration failed to complete in 1ms; "
- "noisy environment?\n");
- return false;
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ }
}
/* Do PA Calibration */
if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah);
- /* Do NF Calibration */
+ /* Do NF Calibration after DC offset and other calibrations */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_NF);
+ REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+ /* Enable IQ, ADC Gain and ADC DC offset CALs */
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC Gain Calibration.\n");
+ "enabling ADC Gain Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC DC Calibration.\n");
+ "enabling ADC DC Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ "enabling IQ Calibration.\n");
}
ah->cal_list_curr = ah->cal_list;
@@ -1009,49 +988,49 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
return true;
}
-const struct hal_percal_data iq_cal_multi_sample = {
+const struct ath9k_percal_data iq_cal_multi_sample = {
IQ_MISMATCH_CAL,
MAX_CAL_SAMPLES,
PER_MIN_LOG_COUNT,
ath9k_hw_iqcal_collect,
ath9k_hw_iqcalibrate
};
-const struct hal_percal_data iq_cal_single_sample = {
+const struct ath9k_percal_data iq_cal_single_sample = {
IQ_MISMATCH_CAL,
MIN_CAL_SAMPLES,
PER_MAX_LOG_COUNT,
ath9k_hw_iqcal_collect,
ath9k_hw_iqcalibrate
};
-const struct hal_percal_data adc_gain_cal_multi_sample = {
+const struct ath9k_percal_data adc_gain_cal_multi_sample = {
ADC_GAIN_CAL,
MAX_CAL_SAMPLES,
PER_MIN_LOG_COUNT,
ath9k_hw_adc_gaincal_collect,
ath9k_hw_adc_gaincal_calibrate
};
-const struct hal_percal_data adc_gain_cal_single_sample = {
+const struct ath9k_percal_data adc_gain_cal_single_sample = {
ADC_GAIN_CAL,
MIN_CAL_SAMPLES,
PER_MAX_LOG_COUNT,
ath9k_hw_adc_gaincal_collect,
ath9k_hw_adc_gaincal_calibrate
};
-const struct hal_percal_data adc_dc_cal_multi_sample = {
+const struct ath9k_percal_data adc_dc_cal_multi_sample = {
ADC_DC_CAL,
MAX_CAL_SAMPLES,
PER_MIN_LOG_COUNT,
ath9k_hw_adc_dccal_collect,
ath9k_hw_adc_dccal_calibrate
};
-const struct hal_percal_data adc_dc_cal_single_sample = {
+const struct ath9k_percal_data adc_dc_cal_single_sample = {
ADC_DC_CAL,
MIN_CAL_SAMPLES,
PER_MAX_LOG_COUNT,
ath9k_hw_adc_dccal_collect,
ath9k_hw_adc_dccal_calibrate
};
-const struct hal_percal_data adc_init_dc_cal = {
+const struct ath9k_percal_data adc_init_dc_cal = {
ADC_DC_INIT_CAL,
MIN_CAL_SAMPLES,
INIT_LOG_COUNT,
diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 1c74bd50700..fe5367f1414 100644
--- a/drivers/net/wireless/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -17,13 +17,13 @@
#ifndef CALIB_H
#define CALIB_H
-extern const struct hal_percal_data iq_cal_multi_sample;
-extern const struct hal_percal_data iq_cal_single_sample;
-extern const struct hal_percal_data adc_gain_cal_multi_sample;
-extern const struct hal_percal_data adc_gain_cal_single_sample;
-extern const struct hal_percal_data adc_dc_cal_multi_sample;
-extern const struct hal_percal_data adc_dc_cal_single_sample;
-extern const struct hal_percal_data adc_init_dc_cal;
+extern const struct ath9k_percal_data iq_cal_multi_sample;
+extern const struct ath9k_percal_data iq_cal_single_sample;
+extern const struct ath9k_percal_data adc_gain_cal_multi_sample;
+extern const struct ath9k_percal_data adc_gain_cal_single_sample;
+extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
+extern const struct ath9k_percal_data adc_dc_cal_single_sample;
+extern const struct ath9k_percal_data adc_init_dc_cal;
#define AR_PHY_CCA_MAX_GOOD_VALUE -85
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
@@ -67,14 +67,14 @@ struct ar5416IniArray {
} \
} while (0)
-enum hal_cal_types {
+enum ath9k_cal_types {
ADC_DC_INIT_CAL = 0x1,
ADC_GAIN_CAL = 0x2,
ADC_DC_CAL = 0x4,
IQ_MISMATCH_CAL = 0x8
};
-enum hal_cal_state {
+enum ath9k_cal_state {
CAL_INACTIVE,
CAL_WAITING,
CAL_RUNNING,
@@ -87,18 +87,18 @@ enum hal_cal_state {
#define PER_MIN_LOG_COUNT 2
#define PER_MAX_LOG_COUNT 10
-struct hal_percal_data {
- enum hal_cal_types calType;
+struct ath9k_percal_data {
+ enum ath9k_cal_types calType;
u32 calNumSamples;
u32 calCountMax;
void (*calCollect) (struct ath_hw *);
void (*calPostProc) (struct ath_hw *, u8);
};
-struct hal_cal_list {
- const struct hal_percal_data *calData;
- enum hal_cal_state calState;
- struct hal_cal_list *calNext;
+struct ath9k_cal_list {
+ const struct ath9k_percal_data *calData;
+ enum ath9k_cal_state calState;
+ struct ath9k_cal_list *calNext;
};
struct ath9k_nfcal_hist {
@@ -116,8 +116,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
- u8 rxchainmask, bool longcal,
- bool *isCalDone);
+ u8 rxchainmask, bool longcal);
bool ath9k_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index fdf9528fa49..97df20cbf52 100644
--- a/drivers/net/wireless/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -498,6 +498,9 @@ int ath9k_init_debug(struct ath_softc *sc)
{
sc->debug.debug_mask = ath9k_debug;
+ if (!ath9k_debugfs_root)
+ return -ENOENT;
+
sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath9k_debugfs_root);
if (!sc->debug.debugfs_phy)
diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 7b0e5419d2b..23298b90b52 100644
--- a/drivers/net/wireless/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -19,20 +19,16 @@
enum ATH_DEBUG {
ATH_DBG_RESET = 0x00000001,
- ATH_DBG_REG_IO = 0x00000002,
- ATH_DBG_QUEUE = 0x00000004,
- ATH_DBG_EEPROM = 0x00000008,
- ATH_DBG_CALIBRATE = 0x00000010,
- ATH_DBG_CHANNEL = 0x00000020,
- ATH_DBG_INTERRUPT = 0x00000040,
- ATH_DBG_REGULATORY = 0x00000080,
- ATH_DBG_ANI = 0x00000100,
- ATH_DBG_POWER_MGMT = 0x00000200,
- ATH_DBG_XMIT = 0x00000400,
- ATH_DBG_BEACON = 0x00001000,
- ATH_DBG_CONFIG = 0x00002000,
- ATH_DBG_KEYCACHE = 0x00004000,
- ATH_DBG_FATAL = 0x00008000,
+ ATH_DBG_QUEUE = 0x00000002,
+ ATH_DBG_EEPROM = 0x00000004,
+ ATH_DBG_CALIBRATE = 0x00000008,
+ ATH_DBG_INTERRUPT = 0x00000010,
+ ATH_DBG_REGULATORY = 0x00000020,
+ ATH_DBG_ANI = 0x00000040,
+ ATH_DBG_XMIT = 0x00000080,
+ ATH_DBG_BEACON = 0x00000100,
+ ATH_DBG_CONFIG = 0x00000200,
+ ATH_DBG_FATAL = 0x00000400,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ffc36b0361c..44fee5ae892 100644
--- a/drivers/net/wireless/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -783,11 +783,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PDADC (%d,%4x): %4.4x %8.8x\n",
i, regChainOffset, regOffset,
reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PDADC: Chain %d | "
"PDADC %3d Value %3d | "
"PDADC %3d Value %3d | "
@@ -910,7 +910,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ah->eep_ops->get_eeprom_rev(ah) <= 2)
twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
"EXT_ADDITIVE %d\n",
ctlMode, numCtlModes, isHt40CtlMode,
@@ -918,7 +918,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
for (i = 0; (i < AR5416_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
"chan %d\n",
@@ -941,7 +941,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
IS_CHAN_2GHZ(chan),
AR5416_EEP4K_NUM_BAND_EDGES);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" MATCH-EE_IDX %d: ch %d is2 %d "
"2xMinEdge %d chainmask %d chains %d\n",
i, freq, IS_CHAN_2GHZ(chan),
@@ -961,7 +961,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" SEL-Min ctlMode %d pCtlMode %d "
"2xMaxEdge %d sP %d minCtlPwr %d\n",
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
@@ -2234,11 +2234,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PDADC (%d,%4x): %4.4x %8.8x\n",
i, regChainOffset, regOffset,
reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PDADC: Chain %d | PDADC %3d "
"Value %3d | PDADC %3d Value %3d | "
"PDADC %3d Value %3d | PDADC %3d "
@@ -2415,14 +2415,14 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
ah->eep_ops->get_eeprom_rev(ah) <= 2)
twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
"EXT_ADDITIVE %d\n",
ctlMode, numCtlModes, isHt40CtlMode,
(pCtlMode[ctlMode] & EXT_ADDITIVE));
for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
"chan %d\n",
@@ -2441,7 +2441,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" MATCH-EE_IDX %d: ch %d is2 %d "
"2xMinEdge %d chainmask %d chains %d\n",
i, freq, IS_CHAN_2GHZ(chan),
@@ -2460,7 +2460,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
minCtlPower = min(twiceMaxEdgePower, scaledPower);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" SEL-Min ctlMode %d pCtlMode %d "
"2xMaxEdge %d sP %d minCtlPwr %d\n",
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 25b68c881ff..7c59dc47f91 100644
--- a/drivers/net/wireless/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -17,6 +17,8 @@
#ifndef EEPROM_H
#define EEPROM_H
+#include <net/cfg80211.h>
+
#define AH_USE_EEPROM 0x1
#ifdef __BIG_ENDIAN
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index b15eaf8417f..ec2a7a40b00 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -97,7 +97,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
udelay(AH_TIME_QUANTUM);
}
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
timeout, reg, REG_READ(ah, reg), mask, val);
@@ -181,7 +181,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Unknown phy %u (rate ix %u)\n",
rates->info[rateix].phy, rateix);
txTime = 0;
@@ -306,7 +306,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (rdData != wrData) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"address test failed "
"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
addr, wrData, rdData);
@@ -318,7 +318,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (wrData != rdData) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"address test failed "
"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
addr, wrData, rdData);
@@ -363,10 +363,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
ah->config.ack_6mb = 0x0;
ah->config.cwm_ignore_extcca = 0;
ah->config.pcie_powersave_enable = 0;
- ah->config.pcie_l1skp_enable = 0;
ah->config.pcie_clock_req = 0;
- ah->config.pcie_power_reset = 0x100;
- ah->config.pcie_restore = 0;
ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1;
ah->config.ht_enable = 1;
@@ -375,13 +372,6 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
ah->config.cck_trig_high = 200;
ah->config.cck_trig_low = 100;
ah->config.enable_ani = 1;
- ah->config.noise_immunity_level = 4;
- ah->config.ofdm_weaksignal_det = 1;
- ah->config.cck_weaksignal_thr = 0;
- ah->config.spur_immunity_level = 2;
- ah->config.firstep_level = 0;
- ah->config.rssi_thr_high = 40;
- ah->config.rssi_thr_low = 7;
ah->config.diversity_control = 0;
ah->config.antenna_switch_swap = 0;
@@ -390,7 +380,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
ah->config.spurchans[i][1] = AR_NO_SPUR;
}
- ah->config.intr_mitigation = 1;
+ ah->config.intr_mitigation = true;
/*
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -463,8 +453,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah)
rfStatus = ath9k_hw_init_rf(ah, &ecode);
if (!rfStatus) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "RF setup failed, status %u\n", ecode);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "RF setup failed, status: %u\n", ecode);
return ecode;
}
@@ -488,10 +478,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
case AR_RAD2122_SREV_MAJOR:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "5G Radio Chip Rev 0x%02X is not "
- "supported by this driver\n",
- ah->hw_version.analog5GhzRev);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Radio Chip Rev 0x%02X not supported\n",
+ val & AR_RADIO_SREV_MAJOR);
return -EOPNOTSUPP;
}
@@ -513,12 +502,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
ah->macaddr[2 * i] = eeval >> 8;
ah->macaddr[2 * i + 1] = eeval & 0xff;
}
- if (sum == 0 || sum == 0xffff * 3) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "mac address read failed: %pM\n",
- ah->macaddr);
+ if (sum == 0 || sum == 0xffff * 3)
return -EADDRNOTAVAIL;
- }
return 0;
}
@@ -575,11 +560,8 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
{
int ecode;
- if (!ath9k_hw_chip_test(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "hardware self-test failed\n");
+ if (!ath9k_hw_chip_test(ah))
return -ENODEV;
- }
ecode = ath9k_hw_rf_claim(ah);
if (ecode != 0)
@@ -617,17 +599,14 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
ath9k_hw_set_defaults(ah);
- if (ah->config.intr_mitigation != 0)
- ah->intr_mitigation = true;
-
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n");
+ DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
ecode = -EIO;
goto bad;
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
+ DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
ecode = -EIO;
goto bad;
}
@@ -650,7 +629,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
(ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
(ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
(!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
- DPRINTF(sc, ATH_DBG_RESET,
+ DPRINTF(sc, ATH_DBG_FATAL,
"Mac Chip Rev 0x%02x.%x is not supported by "
"this driver\n", ah->hw_version.macVersion,
ah->hw_version.macRev);
@@ -690,10 +669,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (AR_SREV_9280_10_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
- DPRINTF(sc, ATH_DBG_RESET,
- "This Mac Chip Rev 0x%02x.%x is \n",
- ah->hw_version.macVersion, ah->hw_version.macRev);
-
if (AR_SREV_9285_12_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
@@ -859,11 +834,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (AR_SREV_9280_20(ah))
ath9k_hw_init_txgain_ini(ah);
- if (!ath9k_hw_fill_cap_info(ah)) {
- DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n");
- ecode = -EINVAL;
- goto bad;
- }
+ ath9k_hw_fill_cap_info(ah);
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
@@ -885,8 +856,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
ecode = ath9k_hw_init_macaddr(ah);
if (ecode != 0) {
- DPRINTF(sc, ATH_DBG_RESET,
- "failed initializing mac address\n");
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Failed to initialize MAC address\n");
goto bad;
}
@@ -1054,7 +1025,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
AR_IMR_RXORN |
AR_IMR_BCNMISC;
- if (ah->intr_mitigation)
+ if (ah->config.intr_mitigation)
ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
else
ah->mask_reg |= AR_IMR_RXOK;
@@ -1203,23 +1174,23 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
switch (ah->hw_version.devid) {
case AR9280_DEVID_PCI:
if (reg == 0x7894) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"ini VAL: %x EEPROM: %x\n", value,
(pBase->version & 0xff));
if ((pBase->version & 0xff) > 0x0a) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PWDCLKIND: %d\n",
pBase->pwdclkind);
value &= ~AR_AN_TOP2_PWDCLKIND;
value |= AR_AN_TOP2_PWDCLKIND &
(pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"PWDCLKIND Earlier Rev\n");
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
"final ini VAL: %x\n", value);
}
break;
@@ -1249,6 +1220,21 @@ static void ath9k_olc_init(struct ath_hw *ah)
ah->PDADCdelta = 0;
}
+static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
+ struct ath9k_channel *chan)
+{
+ u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band);
+
+ if (IS_CHAN_B(chan))
+ ctl |= CTL_11B;
+ else if (IS_CHAN_G(chan))
+ ctl |= CTL_11G;
+ else
+ ctl |= CTL_11A;
+
+ return ctl;
+}
+
static int ath9k_hw_process_ini(struct ath_hw *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode)
@@ -1360,19 +1346,19 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
ath9k_olc_init(ah);
status = ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_ctl(&ah->regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
(u32) ah->regulatory.power_limit));
if (status != 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- "error init'ing transmit power\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Error initializing transmit power\n");
return -EIO;
}
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"ar5416SetRfRegs failed\n");
return -EIO;
}
@@ -1678,7 +1664,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Could not kill baseband RX\n");
return false;
}
@@ -1687,26 +1673,26 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah)) {
if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "failed to set channel\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Failed to set channel\n");
return false;
}
} else {
if (!(ath9k_hw_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "failed to set channel\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Failed to set channel\n");
return false;
}
}
if (ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_ctl(&ah->regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
(u32) ah->regulatory.power_limit)) != 0) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "error init'ing transmit power\n");
+ "Error initializing transmit power\n");
return false;
}
@@ -2199,14 +2185,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ah->txchainmask = sc->tx_chainmask;
ah->rxchainmask = sc->rx_chainmask;
- if (AR_SREV_9285(ah)) {
- ah->txchainmask &= 0x1;
- ah->rxchainmask &= 0x1;
- } else if (AR_SREV_9280(ah)) {
- ah->txchainmask &= 0x3;
- ah->rxchainmask &= 0x3;
- }
-
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO;
@@ -2242,7 +2220,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_mark_phy_inactive(ah);
if (!ath9k_hw_chip_reset(ah, chan)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
@@ -2335,8 +2313,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_OBS, 8);
- if (ah->intr_mitigation) {
-
+ if (ah->config.intr_mitigation) {
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
}
@@ -2385,8 +2362,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
u32 keyType;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "entry %u out of range\n", entry);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2422,8 +2399,8 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
u32 macHi, macLo;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "entry %u out of range\n", entry);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2454,8 +2431,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
u32 keyType;
if (entry >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "entry %u out of range\n", entry);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "keycache entry %u out of range\n", entry);
return false;
}
@@ -2465,7 +2442,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
break;
case ATH9K_CIPHER_AES_CCM:
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"AES-CCM not supported by mac rev 0x%x\n",
ah->hw_version.macRev);
return false;
@@ -2476,14 +2453,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_TKIP;
if (ATH9K_IS_MIC_ENABLED(ah)
&& entry + 64 >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"entry %u inappropriate for TKIP\n", entry);
return false;
}
break;
case ATH9K_CIPHER_WEP:
if (k->kv_len < LEN_WEP40) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"WEP key length %u too small\n", k->kv_len);
return false;
}
@@ -2498,7 +2475,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_CLR;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"cipher %u not supported\n", k->kv_type);
return false;
}
@@ -2716,7 +2693,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
AR_RTC_FORCE_WAKE_EN);
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
return false;
}
@@ -2737,9 +2714,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
"UNDEFINED"
};
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
- modes[ah->power_mode], modes[mode],
- setChip ? "set chip " : "");
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
+ modes[ah->power_mode], modes[mode]);
switch (mode) {
case ATH9K_PM_AWAKE:
@@ -2753,7 +2729,7 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
ath9k_set_power_network_sleep(ah, setChip);
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Unknown power mode %u\n", mode);
return false;
}
@@ -2943,7 +2919,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
*masked = isr & ATH9K_INT_COMMON;
- if (ah->intr_mitigation) {
+ if (ah->config.intr_mitigation) {
if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
*masked |= ATH9K_INT_RX;
}
@@ -3000,6 +2976,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"received PCI PERR interrupt\n");
}
+ *masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
@@ -3061,7 +3038,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
}
if (ints & ATH9K_INT_RX) {
mask |= AR_IMR_RXERR;
- if (ah->intr_mitigation)
+ if (ah->config.intr_mitigation)
mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
else
mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
@@ -3259,7 +3236,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
/* HW Capabilities */
/*******************/
-bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
+void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
u16 capField = 0, eeval;
@@ -3343,8 +3320,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
- pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
-
if (ah->config.ht_enable)
pCap->hw_caps |= ATH9K_HW_CAP_HT;
else
@@ -3368,7 +3343,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->keycache_size = AR_KEYTABLE_SIZE;
pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
- pCap->num_mr_retries = 4;
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
if (AR_SREV_9285_10_OR_LATER(ah))
@@ -3378,14 +3352,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
pCap->num_gpio_pins = AR_NUM_GPIO;
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- pCap->hw_caps |= ATH9K_HW_CAP_WOW;
- pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
- } else {
- pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
- pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
- }
-
if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
pCap->hw_caps |= ATH9K_HW_CAP_CST;
pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
@@ -3411,7 +3377,8 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
(ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
(ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
(ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
- (ah->hw_version.macVersion == AR_SREV_VERSION_9280))
+ (ah->hw_version.macVersion == AR_SREV_VERSION_9280) ||
+ (ah->hw_version.macVersion == AR_SREV_VERSION_9285))
pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
else
pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
@@ -3445,8 +3412,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->btactive_gpio = 6;
ah->wlanactive_gpio = 5;
}
-
- return true;
}
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
@@ -3762,7 +3727,7 @@ bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
if (ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_ctl(&ah->regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 0b594e0ee26..ab3412672e3 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -25,10 +25,11 @@
#include "ani.h"
#include "eeprom.h"
#include "calib.h"
-#include "regd.h"
#include "reg.h"
#include "phy.h"
+#include "../regd.h"
+
#define ATHEROS_VENDOR_ID 0x168c
#define AR5416_DEVID_PCI 0x0023
#define AR5416_DEVID_PCIE 0x0024
@@ -124,29 +125,24 @@ enum wireless_mode {
};
enum ath9k_hw_caps {
- ATH9K_HW_CAP_CHAN_SPREAD = BIT(0),
- ATH9K_HW_CAP_MIC_AESCCM = BIT(1),
- ATH9K_HW_CAP_MIC_CKIP = BIT(2),
- ATH9K_HW_CAP_MIC_TKIP = BIT(3),
- ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4),
- ATH9K_HW_CAP_CIPHER_CKIP = BIT(5),
- ATH9K_HW_CAP_CIPHER_TKIP = BIT(6),
- ATH9K_HW_CAP_VEOL = BIT(7),
- ATH9K_HW_CAP_BSSIDMASK = BIT(8),
- ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9),
- ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10),
- ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11),
- ATH9K_HW_CAP_HT = BIT(12),
- ATH9K_HW_CAP_GTT = BIT(13),
- ATH9K_HW_CAP_FASTCC = BIT(14),
- ATH9K_HW_CAP_RFSILENT = BIT(15),
- ATH9K_HW_CAP_WOW = BIT(16),
- ATH9K_HW_CAP_CST = BIT(17),
- ATH9K_HW_CAP_ENHANCEDPM = BIT(18),
- ATH9K_HW_CAP_AUTOSLEEP = BIT(19),
- ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20),
- ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21),
- ATH9K_HW_CAP_BT_COEX = BIT(22)
+ ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
+ ATH9K_HW_CAP_MIC_CKIP = BIT(1),
+ ATH9K_HW_CAP_MIC_TKIP = BIT(2),
+ ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3),
+ ATH9K_HW_CAP_CIPHER_CKIP = BIT(4),
+ ATH9K_HW_CAP_CIPHER_TKIP = BIT(5),
+ ATH9K_HW_CAP_VEOL = BIT(6),
+ ATH9K_HW_CAP_BSSIDMASK = BIT(7),
+ ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8),
+ ATH9K_HW_CAP_HT = BIT(9),
+ ATH9K_HW_CAP_GTT = BIT(10),
+ ATH9K_HW_CAP_FASTCC = BIT(11),
+ ATH9K_HW_CAP_RFSILENT = BIT(12),
+ ATH9K_HW_CAP_CST = BIT(13),
+ ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
+ ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
+ ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
+ ATH9K_HW_CAP_BT_COEX = BIT(17)
};
enum ath9k_capability_type {
@@ -166,7 +162,6 @@ struct ath9k_hw_capabilities {
u16 keycache_size;
u16 low_5ghz_chan, high_5ghz_chan;
u16 low_2ghz_chan, high_2ghz_chan;
- u16 num_mr_retries;
u16 rts_aggr_limit;
u8 tx_chainmask;
u8 rx_chainmask;
@@ -184,11 +179,8 @@ struct ath9k_ops_config {
int ack_6mb;
int cwm_ignore_extcca;
u8 pcie_powersave_enable;
- u8 pcie_l1skp_enable;
u8 pcie_clock_req;
u32 pcie_waen;
- int pcie_power_reset;
- u8 pcie_restore;
u8 analog_shiftreg;
u8 ht_enable;
u32 ofdm_trig_low;
@@ -196,17 +188,10 @@ struct ath9k_ops_config {
u32 cck_trig_high;
u32 cck_trig_low;
u32 enable_ani;
- u8 noise_immunity_level;
- u32 ofdm_weaksignal_det;
- u32 cck_weaksignal_thr;
- u8 spur_immunity_level;
- u8 firstep_level;
- int8_t rssi_thr_high;
- int8_t rssi_thr_low;
u16 diversity_control;
u16 antenna_switch_swap;
int serialize_regmode;
- int intr_mitigation;
+ bool intr_mitigation;
#define SPUR_DISABLE 0
#define SPUR_ENABLE_IOCTL 1
#define SPUR_ENABLE_EEPROM 2
@@ -281,13 +266,6 @@ enum ath9k_int {
#define CHANNEL_HT40PLUS 0x20000
#define CHANNEL_HT40MINUS 0x40000
-#define CHANNEL_INTERFERENCE 0x01
-#define CHANNEL_DFS 0x02
-#define CHANNEL_4MS_LIMIT 0x04
-#define CHANNEL_DFS_CLEAR 0x08
-#define CHANNEL_DISALLOW_ADHOC 0x10
-#define CHANNEL_PER_11D_ADHOC 0x20
-
#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
@@ -318,10 +296,6 @@ struct ath9k_channel {
int16_t rawNoiseFloor;
};
-#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
- (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
- (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
- (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
(((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
(((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
@@ -329,7 +303,6 @@ struct ath9k_channel {
#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
-#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
#define IS_CHAN_A_5MHZ_SPACED(_c) \
@@ -420,7 +393,7 @@ struct ath_hw {
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
- struct ath9k_regulatory regulatory;
+ struct ath_regulatory regulatory;
struct ath9k_channel channels[38];
struct ath9k_channel *curchan;
@@ -463,14 +436,14 @@ struct ath_hw {
enum ath9k_ant_setting diversity_control;
/* Calibration */
- enum hal_cal_types supp_cals;
- struct hal_cal_list iq_caldata;
- struct hal_cal_list adcgain_caldata;
- struct hal_cal_list adcdc_calinitdata;
- struct hal_cal_list adcdc_caldata;
- struct hal_cal_list *cal_list;
- struct hal_cal_list *cal_list_last;
- struct hal_cal_list *cal_list_curr;
+ enum ath9k_cal_types supp_cals;
+ struct ath9k_cal_list iq_caldata;
+ struct ath9k_cal_list adcgain_caldata;
+ struct ath9k_cal_list adcdc_calinitdata;
+ struct ath9k_cal_list adcdc_caldata;
+ struct ath9k_cal_list *cal_list;
+ struct ath9k_cal_list *cal_list_last;
+ struct ath9k_cal_list *cal_list_curr;
#define totalPowerMeasI meas0.unsign
#define totalPowerMeasQ meas1.unsign
#define totalIqCorrMeas meas2.sign
@@ -540,7 +513,6 @@ struct ath_hw {
enum ath9k_ani_cmd ani_function;
u32 intr_txqs;
- bool intr_mitigation;
enum ath9k_ht_extprotspacing extprotspacing;
u8 txchainmask;
u8 rxchainmask;
@@ -573,7 +545,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
void ath9k_hw_rfdetach(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
-bool ath9k_hw_fill_cap_info(struct ath_hw *ah);
+void ath9k_hw_fill_cap_info(struct ath_hw *ah);
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
u32 capability, u32 *result);
bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34b79a..e2f0a34b79a 100644
--- a/drivers/net/wireless/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index e0a6dee4583..8ae4ec21667 100644
--- a/drivers/net/wireless/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -49,7 +49,7 @@ bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
{
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
REG_WRITE(ah, AR_Q_TXE, 1 << q);
@@ -110,13 +110,15 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -146,7 +148,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
break;
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "TSF have moved while trying to set "
+ "TSF has moved while trying to set "
"quiet time TSF: 0x%08x\n", tsfLow);
}
@@ -158,8 +160,8 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
wait = wait_time;
while (ath9k_hw_numtxpending(ah, q)) {
if ((--wait) == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
- "Failed to stop Tx DMA in 100 "
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "Failed to stop TX DMA in 100 "
"msec after killing last frame\n");
break;
}
@@ -454,17 +456,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
qi->tqi_ver = qinfo->tqi_ver;
qi->tqi_subtype = qinfo->tqi_subtype;
@@ -521,13 +525,15 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -575,22 +581,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
ATH9K_TX_QUEUE_INACTIVE)
break;
if (q == pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "no available tx queue\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "No available TX queue\n");
return -1;
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n",
+ type);
return -1;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
qi = &ah->txq[q];
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "tx queue %u already active\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "TX queue: %u already active\n", q);
return -1;
}
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -620,16 +627,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
ah->txok_interrupt_mask &= ~(1 << q);
@@ -650,17 +659,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
u32 cwMin, chanCwMin, value;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
+ "inactive queue: %u\n", q);
return true;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
if (chan && IS_CHAN_B(chan))
@@ -894,7 +905,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
reg = REG_READ(ah, AR_OBS_BUS_1);
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
+ "RX failed to go idle in 10 ms RXSM=0x%x\n", reg);
return false;
}
@@ -949,8 +960,8 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "dma failed to stop in %d ms "
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "DMA failed to stop in %d ms "
"AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
AH_RX_STOP_DMA_TIMEOUT / 1000,
REG_READ(ah, AR_CR),
diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 1176bce8b76..1176bce8b76 100644
--- a/drivers/net/wireless/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 13d4e6756c9..2398d4f45f2 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -287,7 +287,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
}
spin_unlock_bh(&sc->sc_resetlock);
- sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
sc->sc_flags &= ~SC_OP_FULL_RESET;
if (ath_startrecv(sc) != 0) {
@@ -368,28 +367,16 @@ static void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
- bool iscaldone = false;
-
- if (ath9k_hw_calibrate(ah, ah->curchan,
- sc->rx_chainmask, longcal,
- &iscaldone)) {
- if (longcal)
- sc->ani.noise_floor =
- ath9k_hw_getchan_noise(ah,
- ah->curchan);
-
- DPRINTF(sc, ATH_DBG_ANI,
- "calibrate chan %u/%x nf: %d\n",
- ah->curchan->channel,
- ah->curchan->channelFlags,
- sc->ani.noise_floor);
- } else {
- DPRINTF(sc, ATH_DBG_ANY,
- "calibrate chan %u/%x failed\n",
- ah->curchan->channel,
- ah->curchan->channelFlags);
- }
- sc->ani.caldone = iscaldone;
+ sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan,
+ sc->rx_chainmask, longcal);
+
+ if (longcal)
+ sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
+ ah->curchan);
+
+ DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n",
+ ah->curchan->channel, ah->curchan->channelFlags,
+ sc->ani.noise_floor);
}
}
@@ -408,6 +395,18 @@ set_timer:
mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
}
+static void ath_start_ani(struct ath_softc *sc)
+{
+ unsigned long timestamp = jiffies_to_msecs(jiffies);
+
+ sc->ani.longcal_timer = timestamp;
+ sc->ani.shortcal_timer = timestamp;
+ sc->ani.checkani_timer = timestamp;
+
+ mod_timer(&sc->ani.timer,
+ jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+}
+
/*
* Update tx/rx chainmask. For legacy association,
* hard code chainmask to 1x1, for 11n association, use
@@ -416,7 +415,6 @@ set_timer:
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
- sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
if (is_ht ||
(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
@@ -436,12 +434,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
an = (struct ath_node *)sta->drv_priv;
- if (sc->sc_flags & SC_OP_TXAGGR)
+ if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an);
-
- an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
- sta->ht_cap.ampdu_factor);
- an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ sta->ht_cap.ampdu_factor);
+ an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ }
}
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -458,133 +456,124 @@ static void ath9k_tasklet(unsigned long data)
u32 status = sc->intrstatus;
if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
ath_reset(sc, false);
return;
- } else {
+ }
- if (status &
- (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
- spin_lock_bh(&sc->rx.rxflushlock);
- ath_rx_tasklet(sc, 0);
- spin_unlock_bh(&sc->rx.rxflushlock);
- }
- /* XXX: optimize this */
- if (status & ATH9K_INT_TX)
- ath_tx_tasklet(sc);
+ if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+ spin_lock_bh(&sc->rx.rxflushlock);
+ ath_rx_tasklet(sc, 0);
+ spin_unlock_bh(&sc->rx.rxflushlock);
}
+ if (status & ATH9K_INT_TX)
+ ath_tx_tasklet(sc);
+
/* re-enable hardware interrupt */
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
}
irqreturn_t ath_isr(int irq, void *dev)
{
+#define SCHED_INTR ( \
+ ATH9K_INT_FATAL | \
+ ATH9K_INT_RXORN | \
+ ATH9K_INT_RXEOL | \
+ ATH9K_INT_RX | \
+ ATH9K_INT_TX | \
+ ATH9K_INT_BMISS | \
+ ATH9K_INT_CST | \
+ ATH9K_INT_TSFOOR)
+
struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah;
enum ath9k_int status;
bool sched = false;
- do {
- if (sc->sc_flags & SC_OP_INVALID) {
- /*
- * The hardware is not ready/present, don't
- * touch anything. Note this can happen early
- * on if the IRQ is shared.
- */
- return IRQ_NONE;
- }
- if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
- return IRQ_NONE;
- }
+ /*
+ * The hardware is not ready/present, don't
+ * touch anything. Note this can happen early
+ * on if the IRQ is shared.
+ */
+ if (sc->sc_flags & SC_OP_INVALID)
+ return IRQ_NONE;
- /*
- * Figure out the reason(s) for the interrupt. Note
- * that the hal returns a pseudo-ISR that may include
- * bits we haven't explicitly enabled so we mask the
- * value to insure we only process bits we requested.
- */
- ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
+ ath9k_ps_wakeup(sc);
+
+ /* shared irq, not for us */
+
+ if (!ath9k_hw_intrpend(ah)) {
+ ath9k_ps_restore(sc);
+ return IRQ_NONE;
+ }
+
+ /*
+ * Figure out the reason(s) for the interrupt. Note
+ * that the hal returns a pseudo-ISR that may include
+ * bits we haven't explicitly enabled so we mask the
+ * value to insure we only process bits we requested.
+ */
+ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
+ status &= sc->imask; /* discard unasked-for bits */
+
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
+ */
+ if (!status) {
+ ath9k_ps_restore(sc);
+ return IRQ_NONE;
+ }
+
+ /* Cache the status */
+ sc->intrstatus = status;
- status &= sc->imask; /* discard unasked-for bits */
+ if (status & SCHED_INTR)
+ sched = true;
+ /*
+ * If a FATAL or RXORN interrupt is received, we have to reset the
+ * chip immediately.
+ */
+ if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN))
+ goto chip_reset;
+
+ if (status & ATH9K_INT_SWBA)
+ tasklet_schedule(&sc->bcon_tasklet);
+
+ if (status & ATH9K_INT_TXURN)
+ ath9k_hw_updatetxtriglevel(ah, true);
+
+ if (status & ATH9K_INT_MIB) {
/*
- * If there are no status bits set, then this interrupt was not
- * for me (should have been caught above).
+ * Disable interrupts until we service the MIB
+ * interrupt; otherwise it will continue to
+ * fire.
*/
- if (!status)
- return IRQ_NONE;
-
- sc->intrstatus = status;
- ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(ah, 0);
+ /*
+ * Let the hal handle the event. We assume
+ * it will clear whatever condition caused
+ * the interrupt.
+ */
+ ath9k_hw_procmibevent(ah, &sc->nodestats);
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
- if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
+ if (status & ATH9K_INT_TIM_TIMER) {
+ if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ /* Clear RxAbort bit so that we can
+ * receive frames */
+ ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
+ ath9k_hw_setrxabort(ah, 0);
sched = true;
- } else if (status & ATH9K_INT_RXORN) {
- /* need a chip reset */
- sched = true;
- } else {
- if (status & ATH9K_INT_SWBA) {
- /* schedule a tasklet for beacon handling */
- tasklet_schedule(&sc->bcon_tasklet);
- }
- if (status & ATH9K_INT_RXEOL) {
- /*
- * NB: the hardware should re-read the link when
- * RXE bit is written, but it doesn't work
- * at least on older hardware revs.
- */
- sched = true;
- }
-
- if (status & ATH9K_INT_TXURN)
- /* bump tx trigger level */
- ath9k_hw_updatetxtriglevel(ah, true);
- /* XXX: optimize this */
- if (status & ATH9K_INT_RX)
- sched = true;
- if (status & ATH9K_INT_TX)
- sched = true;
- if (status & ATH9K_INT_BMISS)
- sched = true;
- /* carrier sense timeout */
- if (status & ATH9K_INT_CST)
- sched = true;
- if (status & ATH9K_INT_MIB) {
- /*
- * Disable interrupts until we service the MIB
- * interrupt; otherwise it will continue to
- * fire.
- */
- ath9k_hw_set_interrupts(ah, 0);
- /*
- * Let the hal handle the event. We assume
- * it will clear whatever condition caused
- * the interrupt.
- */
- ath9k_hw_procmibevent(ah, &sc->nodestats);
- ath9k_hw_set_interrupts(ah, sc->imask);
- }
- if (status & ATH9K_INT_TIM_TIMER) {
- if (!(ah->caps.hw_caps &
- ATH9K_HW_CAP_AUTOSLEEP)) {
- /* Clear RxAbort bit so that we can
- * receive frames */
- ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
- ath9k_hw_setrxabort(ah, 0);
- sched = true;
- sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
- }
- }
- if (status & ATH9K_INT_TSFOOR) {
- /* FIXME: Handle this interrupt for power save */
- sched = true;
- }
+ sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
- ath9k_ps_restore(sc);
- } while (0);
+ }
+chip_reset:
+
+ ath9k_ps_restore(sc);
ath_debug_stat_interrupt(sc, status);
if (sched) {
@@ -594,6 +583,8 @@ irqreturn_t ath_isr(int irq, void *dev)
}
return IRQ_HANDLED;
+
+#undef SCHED_INTR
}
static u32 ath_get_extchanmode(struct ath_softc *sc,
@@ -676,7 +667,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
- DPRINTF(sc, ATH_DBG_KEYCACHE,
+ DPRINTF(sc, ATH_DBG_FATAL,
"Setting TX MIC Key Failed\n");
return 0;
}
@@ -920,11 +911,9 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
- /* Start ANI */
- mod_timer(&sc->ani.timer,
- jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+ ath_start_ani(sc);
} else {
- DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
+ DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
}
}
@@ -1098,10 +1087,10 @@ void ath_radio_enable(struct ath_softc *sc)
int r;
ath9k_ps_wakeup(sc);
- spin_lock_bh(&sc->sc_resetlock);
+ ath9k_hw_configpcipowersave(ah, 0);
+ spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
-
if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset channel %u (%uMhz) ",
@@ -1163,6 +1152,7 @@ void ath_radio_disable(struct ath_softc *sc)
spin_unlock_bh(&sc->sc_resetlock);
ath9k_hw_phy_disable(ah);
+ ath9k_hw_configpcipowersave(ah, 1);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
ath9k_ps_restore(sc);
}
@@ -1267,7 +1257,6 @@ static int ath_init_sw_rfkill(struct ath_softc *sc)
sc->rf_kill.rfkill->data = sc;
sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
- sc->rf_kill.rfkill->user_claim_unsupported = 1;
return 0;
}
@@ -1362,6 +1351,17 @@ void ath_detach(struct ath_softc *sc)
ath9k_ps_restore(sc);
}
+static int ath9k_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_regulatory *reg = &sc->sc_ah->regulatory;
+
+ return ath_reg_notifier_apply(wiphy, request, reg);
+}
+
static int ath_init(u16 devid, struct ath_softc *sc)
{
struct ath_hw *ah = NULL;
@@ -1403,7 +1403,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
if (sc->keymax > ATH_KEYMAX) {
- DPRINTF(sc, ATH_DBG_KEYCACHE,
+ DPRINTF(sc, ATH_DBG_ANY,
"Warning, using only %u entries in %u key cache\n",
ATH_KEYMAX, sc->keymax);
sc->keymax = ATH_KEYMAX;
@@ -1416,7 +1416,9 @@ static int ath_init(u16 devid, struct ath_softc *sc)
for (i = 0; i < sc->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
- if (ath9k_regd_init(sc->sc_ah))
+ error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
+ ath9k_reg_notifier);
+ if (error)
goto bad;
/* default to MONITOR mode */
@@ -1545,9 +1547,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
sc->beacon.bslot_aphy[i] = NULL;
}
- /* save MISC configurations */
- sc->config.swBeaconProcess = 1;
-
/* setup channels and rates */
sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
@@ -1602,9 +1601,6 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->wiphy->reg_notifier = ath9k_reg_notifier;
- hw->wiphy->strict_regulatory = true;
-
hw->queues = 4;
hw->max_rates = 4;
hw->channel_change_time = 5000;
@@ -1625,8 +1621,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
int ath_attach(u16 devid, struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
- const struct ieee80211_regdomain *regd;
int error = 0, i;
+ struct ath_regulatory *reg;
DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
@@ -1634,6 +1630,8 @@ int ath_attach(u16 devid, struct ath_softc *sc)
if (error != 0)
return error;
+ reg = &sc->sc_ah->regulatory;
+
/* get mac address from hardware and set in mac80211 */
SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
@@ -1666,31 +1664,14 @@ int ath_attach(u16 devid, struct ath_softc *sc)
goto error_attach;
#endif
- if (ath9k_is_world_regd(sc->sc_ah)) {
- /* Anything applied here (prior to wiphy registration) gets
- * saved on the wiphy orig_* parameters */
- regd = ath9k_world_regdomain(sc->sc_ah);
- hw->wiphy->custom_regulatory = true;
- hw->wiphy->strict_regulatory = false;
- } else {
- /* This gets applied in the case of the absense of CRDA,
- * it's our own custom world regulatory domain, similar to
- * cfg80211's but we enable passive scanning */
- regd = ath9k_default_world_regdomain();
- }
- wiphy_apply_custom_regulatory(hw->wiphy, regd);
- ath9k_reg_apply_radar_flags(hw->wiphy);
- ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER);
-
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(500);
error = ieee80211_register_hw(hw);
- if (!ath9k_is_world_regd(sc->sc_ah)) {
- error = regulatory_hint(hw->wiphy,
- sc->sc_ah->regulatory.alpha2);
+ if (!ath_is_world_regd(reg)) {
+ error = regulatory_hint(hw->wiphy, reg->alpha2);
if (error)
goto error_attach;
}
@@ -1792,7 +1773,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
goto fail;
}
- dd->dd_name = name;
dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
/*
@@ -1822,7 +1802,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
}
ds = dd->dd_desc;
DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
- dd->dd_name, ds, (u32) dd->dd_desc_len,
+ name, ds, (u32) dd->dd_desc_len,
ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
/* allocate buffers */
@@ -2043,8 +2023,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
* here except setup the interrupt mask.
*/
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to start recv logic\n");
+ DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
r = -EIO;
goto mutex_unlock;
}
@@ -2257,25 +2236,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
sc->imask |= ATH9K_INT_TSFOOR;
}
- /*
- * Some hardware processes the TIM IE and fires an
- * interrupt when the TIM bit is set. For hardware
- * that does, if not overridden by configuration,
- * enable the TIM interrupt when operating as station.
- */
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
- (conf->type == NL80211_IFTYPE_STATION) &&
- !sc->config.swBeaconProcess)
- sc->imask |= ATH9K_INT_TIM;
-
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP) {
- /* TODO: is this a suitable place to start ANI for AP mode? */
- /* Start ANI */
- mod_timer(&sc->ani.timer,
- jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
- }
+ if (conf->type == NL80211_IFTYPE_AP)
+ ath_start_ani(sc);
out:
mutex_unlock(&sc->mutex);
@@ -2326,26 +2290,33 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf;
+ struct ath_hw *ah = sc->sc_ah;
mutex_lock(&sc->mutex);
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
- if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
- sc->imask |= ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(sc->sc_ah,
- sc->imask);
+ if (!(ah->caps.hw_caps &
+ ATH9K_HW_CAP_AUTOSLEEP)) {
+ if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
+ sc->imask |= ATH9K_INT_TIM_TIMER;
+ ath9k_hw_set_interrupts(sc->sc_ah,
+ sc->imask);
+ }
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
}
- ath9k_hw_setrxabort(sc->sc_ah, 1);
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
} else {
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- ath9k_hw_setrxabort(sc->sc_ah, 0);
- sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
- if (sc->imask & ATH9K_INT_TIM_TIMER) {
- sc->imask &= ~ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(sc->sc_ah,
- sc->imask);
+ if (!(ah->caps.hw_caps &
+ ATH9K_HW_CAP_AUTOSLEEP)) {
+ ath9k_hw_setrxabort(sc->sc_ah, 0);
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+ if (sc->imask & ATH9K_INT_TIM_TIMER) {
+ sc->imask &= ~ATH9K_INT_TIM_TIMER;
+ ath9k_hw_set_interrupts(sc->sc_ah,
+ sc->imask);
+ }
}
}
}
@@ -2562,6 +2533,8 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
mutex_lock(&sc->mutex);
+ memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+
qi.tqi_aifs = params->aifs;
qi.tqi_cwmin = params->cw_min;
qi.tqi_cwmax = params->cw_max;
@@ -2598,7 +2571,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
- DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
+ DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
@@ -2771,6 +2744,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
+ sc->sc_flags |= SC_OP_FULL_RESET;
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 6dbc58580ab..6dbc58580ab 100644
--- a/drivers/net/wireless/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index 8bcba906929..5ec9ce91d97 100644
--- a/drivers/net/wireless/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -46,7 +46,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ((freq - 704) * 2 - 3040) / 10;
bModeSynth = 1;
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Invalid channel %u MHz\n", freq);
return false;
}
@@ -79,7 +79,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Invalid channel %u MHz\n", freq);
return false;
}
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 0f7f8e0c9c9..296d0e985f2 100644
--- a/drivers/net/wireless/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -556,9 +556,6 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
int r; \
for (r = 0; r < ((iniarray)->ia_rows); r++) { \
REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, \
- "RF 0x%x V 0x%x\n", \
- INI_RA((iniarray), r, 0), (regData)[r]); \
DO_DELAY(regWr); \
} \
} while (0)
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 824ccbb8b7b..8f3cf10f65c 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -524,7 +524,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
u32 valid;
for (i = 0; i < rate_table->rate_cnt; i++) {
- valid = (ath_rc_priv->single_stream ?
+ valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
rate_table->info[i].valid_single_stream :
rate_table->info[i].valid);
if (valid == 1) {
@@ -557,9 +557,9 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
- u32 valid = (ath_rc_priv->single_stream ?
- rate_table->info[j].valid_single_stream :
- rate_table->info[j].valid);
+ u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
+ rate_table->info[j].valid_single_stream :
+ rate_table->info[j].valid);
u8 rate = rateset->rs_rates[i];
u8 dot11rate = rate_table->info[j].dot11rate;
@@ -603,7 +603,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
- u32 valid = (ath_rc_priv->single_stream ?
+ u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
u8 rate = rateset->rs_rates[i];
@@ -740,9 +740,10 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
+ ASSERT((rate_table->info[rate].valid &&
+ (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
(rate_table->info[rate].valid_single_stream &&
- ath_rc_priv->single_stream));
+ !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
return rate;
}
@@ -811,7 +812,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
u16 min_rate)
{
u32 j;
- u8 nextindex;
+ u8 nextindex = 0;
if (min_rate) {
for (j = RATE_TABLE_SIZE; j > 0; j--) {
@@ -1320,7 +1321,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
* 40 to 20 => don't update */
if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
- (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG))
+ !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
return;
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
@@ -1345,9 +1346,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
/* If HT40 and we have switched mode from 40 to 20 => don't update */
if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
- (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) {
+ !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
return;
- }
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
@@ -1420,10 +1420,6 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->valid_phy_rateidx[i][j] = 0;
ath_rc_priv->valid_phy_ratecnt[i] = 0;
}
- ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG;
-
- /* Set stream capability */
- ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
if (!rateset->rs_nrates) {
/* No working rate, just initialize valid rates */
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 199a3ce57d6..e3abd76103f 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -24,7 +24,6 @@ struct ath_softc;
#define ATH_RATE_MAX 30
#define RATE_TABLE_SIZE 64
#define MAX_TX_RATE_PHY 48
-#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
/* VALID_ALL - valid for 20/40/Legacy,
* VALID - Legacy only,
@@ -158,7 +157,6 @@ struct ath_rateset {
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
- * @single_stream: When TRUE, only single TX stream possible
* @neg_rates: Negotatied rates
* @neg_ht_rates: Negotiated HT rates
*/
@@ -176,10 +174,8 @@ struct ath_rate_priv {
u8 max_valid_rate;
u8 valid_rate_index[RATE_TABLE_SIZE];
u8 ht_cap;
- u8 single_stream;
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
- u8 rc_phy_mode;
u8 rate_max_phy;
u32 rssi_time;
u32 rssi_down_time;
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index dd1f3015674..b46badd21f7 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -283,54 +283,51 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
struct ath_buf *bf;
int error = 0;
- do {
- spin_lock_init(&sc->rx.rxflushlock);
- sc->sc_flags &= ~SC_OP_RXFLUSH;
- spin_lock_init(&sc->rx.rxbuflock);
-
- sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(sc->cachelsz,
- (u16)64));
+ spin_lock_init(&sc->rx.rxflushlock);
+ sc->sc_flags &= ~SC_OP_RXFLUSH;
+ spin_lock_init(&sc->rx.rxbuflock);
- DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- sc->cachelsz, sc->rx.bufsize);
+ sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+ min(sc->cachelsz, (u16)64));
- /* Initialize rx descriptors */
+ DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+ sc->cachelsz, sc->rx.bufsize);
- error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
- "rx", nbufs, 1);
- if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "failed to allocate rx descriptors: %d\n", error);
- break;
- }
+ /* Initialize rx descriptors */
- list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
- if (skb == NULL) {
- error = -ENOMEM;
- break;
- }
+ error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
+ "rx", nbufs, 1);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "failed to allocate rx descriptors: %d\n", error);
+ goto err;
+ }
- bf->bf_mpdu = skb;
- bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
- sc->rx.bufsize,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(sc->dev,
- bf->bf_buf_addr))) {
- dev_kfree_skb_any(skb);
- bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "dma_mapping_error() on RX init\n");
- error = -ENOMEM;
- break;
- }
- bf->bf_dmacontext = bf->bf_buf_addr;
+ list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+ skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
+ if (skb == NULL) {
+ error = -ENOMEM;
+ goto err;
}
- sc->rx.rxlink = NULL;
- } while (0);
+ bf->bf_mpdu = skb;
+ bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+ sc->rx.bufsize,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(sc->dev,
+ bf->bf_buf_addr))) {
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "dma_mapping_error() on RX init\n");
+ error = -ENOMEM;
+ goto err;
+ }
+ bf->bf_dmacontext = bf->bf_buf_addr;
+ }
+ sc->rx.rxlink = NULL;
+err:
if (error)
ath_rx_cleanup(sc);
@@ -345,10 +342,8 @@ void ath_rx_cleanup(struct ath_softc *sc)
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
skb = bf->bf_mpdu;
if (skb) {
- dma_unmap_single(sc->dev,
- bf->bf_buf_addr,
- sc->rx.bufsize,
- DMA_FROM_DEVICE);
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
+ sc->rx.bufsize, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
}
@@ -675,7 +670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_CONFIG,
+ DPRINTF(sc, ATH_DBG_FATAL,
"dma_mapping_error() on RX\n");
break;
}
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 52605246679..52605246679 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 1ff429b027d..1ff429b027d 100644
--- a/drivers/net/wireless/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 689bdbf7880..faf2cab49ea 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -283,7 +283,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
- skb = (struct sk_buff *)bf->bf_mpdu;
+ skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
rcu_read_lock();
@@ -380,8 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
} else {
/* retry the un-acked ones */
- if (bf->bf_next == NULL &&
- bf_last->bf_status & ATH_BUFSTATUS_STALE) {
+ if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last);
@@ -444,7 +443,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
u16 aggr_limit, legacy = 0, maxampdu;
int i;
- skb = (struct sk_buff *)bf->bf_mpdu;
+ skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
rates = tx_info->control.rates;
tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
@@ -1004,7 +1003,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ if (bf->bf_stale) {
list_del(&bf->list);
spin_unlock_bh(&txq->axq_lock);
@@ -1452,7 +1451,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
- skb = (struct sk_buff *)bf->bf_mpdu;
+ skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
rates = tx_info->control.rates;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -1573,8 +1572,9 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "dma_mapping_error() on TX\n");
+ kfree(tx_info_priv);
+ tx_info->rate_driver_data[0] = NULL;
+ DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n");
return -ENOMEM;
}
@@ -1586,7 +1586,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_control *txctl)
{
- struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_node *an = NULL;
@@ -1860,7 +1860,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
int nbad, int txok, bool update_rc)
{
- struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
@@ -1941,7 +1941,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
* it with the STALE flag.
*/
bf_held = NULL;
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
txq->axq_link = NULL;
@@ -1982,7 +1982,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
* however leave the last descriptor back as the holding
* descriptor for hw.
*/
- lastbf->bf_status |= ATH_BUFSTATUS_STALE;
+ lastbf->bf_stale = true;
INIT_LIST_HEAD(&bf_head);
if (!list_is_singular(&lastbf->list))
list_cut_position(&bf_head,
@@ -2048,44 +2048,38 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
{
int error = 0;
- do {
- spin_lock_init(&sc->tx.txbuflock);
+ spin_lock_init(&sc->tx.txbuflock);
- error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
- "tx", nbufs, 1);
- if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate tx descriptors: %d\n",
- error);
- break;
- }
-
- error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
- "beacon", ATH_BCBUF, 1);
- if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate beacon descriptors: %d\n",
- error);
- break;
- }
+ error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
+ "tx", nbufs, 1);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Failed to allocate tx descriptors: %d\n", error);
+ goto err;
+ }
- } while (0);
+ error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
+ "beacon", ATH_BCBUF, 1);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Failed to allocate beacon descriptors: %d\n", error);
+ goto err;
+ }
+err:
if (error != 0)
ath_tx_cleanup(sc);
return error;
}
-int ath_tx_cleanup(struct ath_softc *sc)
+void ath_tx_cleanup(struct ath_softc *sc)
{
if (sc->beacon.bdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
if (sc->tx.txdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
-
- return 0;
}
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
new file mode 100644
index 00000000000..9949b11cb15
--- /dev/null
+++ b/drivers/net/wireless/ath/main.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath/regd.c
index 4ca62510229..fdf07c82208 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -16,7 +16,9 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#include "ath9k.h"
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include "regd.h"
#include "regd_common.h"
/*
@@ -55,7 +57,7 @@
/* Can be used for:
* 0x60, 0x61, 0x62 */
-static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
+static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
.n_reg_rules = 5,
.alpha2 = "99",
.reg_rules = {
@@ -65,7 +67,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
};
/* Can be used by 0x63 and 0x65 */
-static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
+static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
@@ -76,7 +78,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
};
/* Can be used by 0x64 only */
-static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
+static const struct ieee80211_regdomain ath_world_regdom_64 = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
@@ -86,7 +88,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
};
/* Can be used by 0x66 and 0x69 */
-static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
+static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
@@ -96,7 +98,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
};
/* Can be used by 0x67, 0x6A and 0x68 */
-static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
+static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
@@ -112,49 +114,51 @@ static inline bool is_wwr_sku(u16 regd)
(regd == WORLD);
}
-static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
+static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
{
- return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
+ return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
}
-bool ath9k_is_world_regd(struct ath_hw *ah)
+bool ath_is_world_regd(struct ath_regulatory *reg)
{
- return is_wwr_sku(ath9k_regd_get_eepromRD(ah));
+ return is_wwr_sku(ath_regd_get_eepromRD(reg));
}
+EXPORT_SYMBOL(ath_is_world_regd);
-const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
+static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
{
/* this is the most restrictive */
- return &ath9k_world_regdom_64;
+ return &ath_world_regdom_64;
}
-const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah)
+static const struct
+ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{
- switch (ah->regulatory.regpair->regDmnEnum) {
+ switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x61:
case 0x62:
- return &ath9k_world_regdom_60_61_62;
+ return &ath_world_regdom_60_61_62;
case 0x63:
case 0x65:
- return &ath9k_world_regdom_63_65;
+ return &ath_world_regdom_63_65;
case 0x64:
- return &ath9k_world_regdom_64;
+ return &ath_world_regdom_64;
case 0x66:
case 0x69:
- return &ath9k_world_regdom_66_69;
+ return &ath_world_regdom_66_69;
case 0x67:
case 0x68:
case 0x6A:
- return &ath9k_world_regdom_67_68_6A;
+ return &ath_world_regdom_67_68_6A;
default:
WARN_ON(1);
- return ath9k_default_world_regdomain();
+ return ath_default_world_regdomain();
}
}
/* Frequency is one where radar detection is required */
-static bool ath9k_is_radar_freq(u16 center_freq)
+static bool ath_is_radar_freq(u16 center_freq)
{
return (center_freq >= 5260 && center_freq <= 5700);
}
@@ -168,9 +172,9 @@ static bool ath9k_is_radar_freq(u16 center_freq)
* received a beacon on a channel we can enable active scan and
* adhoc (or beaconing).
*/
-static void ath9k_reg_apply_beaconing_flags(
- struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator)
+static void
+ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
@@ -191,7 +195,7 @@ static void ath9k_reg_apply_beaconing_flags(
ch = &sband->channels[i];
- if (ath9k_is_radar_freq(ch->center_freq) ||
+ if (ath_is_radar_freq(ch->center_freq) ||
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
@@ -227,9 +231,9 @@ static void ath9k_reg_apply_beaconing_flags(
}
/* Allows active scan scan on Ch 12 and 13 */
-static void ath9k_reg_apply_active_scan_flags(
- struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator)
+static void
+ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
@@ -278,7 +282,7 @@ static void ath9k_reg_apply_active_scan_flags(
}
/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
-void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
+static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
@@ -291,7 +295,7 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
- if (!ath9k_is_radar_freq(ch->center_freq))
+ if (!ath_is_radar_freq(ch->center_freq))
continue;
/* We always enable radar detection/DFS on this
* frequency range. Additionally we also apply on
@@ -310,37 +314,31 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
}
}
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator)
+static void ath_reg_apply_world_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct ath_regulatory *reg)
{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- struct ath_hw *ah = sc->sc_ah;
-
- switch (ah->regulatory.regpair->regDmnEnum) {
+ switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x63:
case 0x66:
case 0x67:
- ath9k_reg_apply_beaconing_flags(wiphy, initiator);
+ ath_reg_apply_beaconing_flags(wiphy, initiator);
break;
case 0x68:
- ath9k_reg_apply_beaconing_flags(wiphy, initiator);
- ath9k_reg_apply_active_scan_flags(wiphy, initiator);
+ ath_reg_apply_beaconing_flags(wiphy, initiator);
+ ath_reg_apply_active_scan_flags(wiphy, initiator);
break;
}
return;
}
-int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+int ath_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct ath_regulatory *reg)
{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
-
/* We always apply this */
- ath9k_reg_apply_radar_flags(wiphy);
+ ath_reg_apply_radar_flags(wiphy);
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@@ -348,17 +346,19 @@ int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
case NL80211_REGDOM_SET_BY_USER:
break;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
- if (ath9k_is_world_regd(sc->sc_ah))
- ath9k_reg_apply_world_flags(wiphy, request->initiator);
+ if (ath_is_world_regd(reg))
+ ath_reg_apply_world_flags(wiphy, request->initiator,
+ reg);
break;
}
return 0;
}
+EXPORT_SYMBOL(ath_reg_notifier_apply);
-bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
+static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
{
- u16 rd = ath9k_regd_get_eepromRD(ah);
+ u16 rd = ath_regd_get_eepromRD(reg);
int i;
if (rd & COUNTRY_ERD_FLAG) {
@@ -373,14 +373,14 @@ bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
if (regDomainPairs[i].regDmnEnum == rd)
return true;
}
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "invalid regulatory domain/country code 0x%x\n", rd);
+ printk(KERN_DEBUG
+ "ath: invalid regulatory domain/country code 0x%x\n", rd);
return false;
}
/* EEPROM country code to regpair mapping */
static struct country_code_to_enum_rd*
-ath9k_regd_find_country(u16 countryCode)
+ath_regd_find_country(u16 countryCode)
{
int i;
@@ -393,7 +393,7 @@ ath9k_regd_find_country(u16 countryCode)
/* EEPROM rd code to regpair mapping */
static struct country_code_to_enum_rd*
-ath9k_regd_find_country_by_rd(int regdmn)
+ath_regd_find_country_by_rd(int regdmn)
{
int i;
@@ -405,13 +405,13 @@ ath9k_regd_find_country_by_rd(int regdmn)
}
/* Returns the map of the EEPROM set RD to a country code */
-static u16 ath9k_regd_get_default_country(u16 rd)
+static u16 ath_regd_get_default_country(u16 rd)
{
if (rd & COUNTRY_ERD_FLAG) {
struct country_code_to_enum_rd *country = NULL;
u16 cc = rd & ~COUNTRY_ERD_FLAG;
- country = ath9k_regd_find_country(cc);
+ country = ath_regd_find_country(cc);
if (country != NULL)
return cc;
}
@@ -420,7 +420,7 @@ static u16 ath9k_regd_get_default_country(u16 rd)
}
static struct reg_dmn_pair_mapping*
-ath9k_get_regpair(int regdmn)
+ath_get_regpair(int regdmn)
{
int i;
@@ -433,87 +433,120 @@ ath9k_get_regpair(int regdmn)
return NULL;
}
-int ath9k_regd_init(struct ath_hw *ah)
+static int
+ath_regd_init_wiphy(struct ath_regulatory *reg,
+ struct wiphy *wiphy,
+ int (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request))
+{
+ const struct ieee80211_regdomain *regd;
+
+ wiphy->reg_notifier = reg_notifier;
+ wiphy->strict_regulatory = true;
+
+ if (ath_is_world_regd(reg)) {
+ /*
+ * Anything applied here (prior to wiphy registration) gets
+ * saved on the wiphy orig_* parameters
+ */
+ regd = ath_world_regdomain(reg);
+ wiphy->custom_regulatory = true;
+ wiphy->strict_regulatory = false;
+ } else {
+ /*
+ * This gets applied in the case of the absense of CRDA,
+ * it's our own custom world regulatory domain, similar to
+ * cfg80211's but we enable passive scanning.
+ */
+ regd = ath_default_world_regdomain();
+ }
+ wiphy_apply_custom_regulatory(wiphy, regd);
+ ath_reg_apply_radar_flags(wiphy);
+ ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+ return 0;
+}
+
+int
+ath_regd_init(struct ath_regulatory *reg,
+ struct wiphy *wiphy,
+ int (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request))
{
struct country_code_to_enum_rd *country = NULL;
u16 regdmn;
- if (!ath9k_regd_is_eeprom_valid(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "Invalid EEPROM contents\n");
+ if (!ath_regd_is_eeprom_valid(reg)) {
+ printk(KERN_ERR "ath: Invalid EEPROM contents\n");
return -EINVAL;
}
- regdmn = ath9k_regd_get_eepromRD(ah);
- ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);
+ regdmn = ath_regd_get_eepromRD(reg);
+ reg->country_code = ath_regd_get_default_country(regdmn);
- if (ah->regulatory.country_code == CTRY_DEFAULT &&
+ if (reg->country_code == CTRY_DEFAULT &&
regdmn == CTRY_DEFAULT)
- ah->regulatory.country_code = CTRY_UNITED_STATES;
+ reg->country_code = CTRY_UNITED_STATES;
- if (ah->regulatory.country_code == CTRY_DEFAULT) {
+ if (reg->country_code == CTRY_DEFAULT) {
country = NULL;
} else {
- country = ath9k_regd_find_country(ah->regulatory.country_code);
+ country = ath_regd_find_country(reg->country_code);
if (country == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "Country is NULL!!!!, cc= %d\n",
- ah->regulatory.country_code);
+ printk(KERN_DEBUG
+ "ath: Country is NULL!!!!, cc= %d\n",
+ reg->country_code);
return -EINVAL;
} else
regdmn = country->regDmnEnum;
}
- ah->regulatory.regpair = ath9k_get_regpair(regdmn);
+ reg->regpair = ath_get_regpair(regdmn);
- if (!ah->regulatory.regpair) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ if (!reg->regpair) {
+ printk(KERN_DEBUG "ath: "
"No regulatory domain pair found, cannot continue\n");
return -EINVAL;
}
if (!country)
- country = ath9k_regd_find_country_by_rd(regdmn);
+ country = ath_regd_find_country_by_rd(regdmn);
if (country) {
- ah->regulatory.alpha2[0] = country->isoName[0];
- ah->regulatory.alpha2[1] = country->isoName[1];
+ reg->alpha2[0] = country->isoName[0];
+ reg->alpha2[1] = country->isoName[1];
} else {
- ah->regulatory.alpha2[0] = '0';
- ah->regulatory.alpha2[1] = '0';
+ reg->alpha2[0] = '0';
+ reg->alpha2[1] = '0';
}
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "Country alpha2 being used: %c%c\n"
- "Regulatory.Regpair detected: 0x%0x\n",
- ah->regulatory.alpha2[0], ah->regulatory.alpha2[1],
- ah->regulatory.regpair->regDmnEnum);
+ printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
+ reg->alpha2[0], reg->alpha2[1]);
+ printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n",
+ reg->regpair->regDmnEnum);
+ ath_regd_init_wiphy(reg, wiphy, reg_notifier);
return 0;
}
+EXPORT_SYMBOL(ath_regd_init);
-u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
+u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
+ enum ieee80211_band band)
{
- u32 ctl = NO_CTL;
-
- if (!ah->regulatory.regpair ||
- (ah->regulatory.country_code == CTRY_DEFAULT &&
- is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {
- if (IS_CHAN_B(chan))
- ctl = SD_NO_CTL | CTL_11B;
- else if (IS_CHAN_G(chan))
- ctl = SD_NO_CTL | CTL_11G;
- else
- ctl = SD_NO_CTL | CTL_11A;
- return ctl;
+ if (!reg->regpair ||
+ (reg->country_code == CTRY_DEFAULT &&
+ is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
+ return SD_NO_CTL;
}
- if (IS_CHAN_B(chan))
- ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
- else if (IS_CHAN_G(chan))
- ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;
- else
- ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ return reg->regpair->reg_2ghz_ctl;
+ case IEEE80211_BAND_5GHZ:
+ return reg->regpair->reg_5ghz_ctl;
+ default:
+ return NO_CTL;
+ }
- return ctl;
+ return NO_CTL;
}
+EXPORT_SYMBOL(ath_regd_get_band_ctl);
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath/regd.h
index 9f5fbd4eea7..07291ccb23f 100644
--- a/drivers/net/wireless/ath9k/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -17,6 +17,25 @@
#ifndef REGD_H
#define REGD_H
+#include <linux/nl80211.h>
+
+#include <net/cfg80211.h>
+
+#define NO_CTL 0xff
+#define SD_NO_CTL 0xE0
+#define NO_CTL 0xff
+#define CTL_MODE_M 7
+#define CTL_11A 0
+#define CTL_11B 1
+#define CTL_11G 2
+#define CTL_2GHT20 5
+#define CTL_5GHT20 6
+#define CTL_2GHT40 7
+#define CTL_5GHT40 8
+
+#define CTRY_DEBUG 0x1ff
+#define CTRY_DEFAULT 0
+
#define COUNTRY_ERD_FLAG 0x8000
#define WORLDWIDE_ROAMING_FLAG 0x4000
@@ -40,7 +59,7 @@ struct country_code_to_enum_rd {
const char *isoName;
};
-struct ath9k_regulatory {
+struct ath_regulatory {
char alpha2[2];
u16 country_code;
u16 max_power_level;
@@ -233,15 +252,14 @@ enum CountryCode {
CTRY_BELGIUM2 = 5002
};
-bool ath9k_is_world_regd(struct ath_hw *ah);
-const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah);
-const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator);
-void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
-int ath9k_regd_init(struct ath_hw *ah);
-bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah);
-u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan);
-int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+bool ath_is_world_regd(struct ath_regulatory *reg);
+int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
+ int (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request));
+u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
+ enum ieee80211_band band);
+int ath_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct ath_regulatory *reg);
#endif
diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 4d0e298cd1c..4d0e298cd1c 100644
--- a/drivers/net/wireless/ath9k/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index aab71a70ba7..21572e40b79 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -3,7 +3,6 @@ config B43
depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
select SSB
select FW_LOADER
- select HW_RANDOM
---help---
b43 is a driver for the Broadcom 43xx series wireless devices.
@@ -106,6 +105,13 @@ config B43_RFKILL
depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
default y
+# This config option automatically enables b43 HW-RNG support,
+# if the HW-RNG core is enabled.
+config B43_HWRNG
+ bool
+ depends on B43 && (HW_RANDOM = y || HW_RANDOM = B43)
+ default y
+
config B43_DEBUG
bool "Broadcom 43xx debugging"
depends on B43
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index beaf18d6e8a..4e8ad841c3c 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -625,9 +625,11 @@ struct b43_wl {
/* Stats about the wireless interface */
struct ieee80211_low_level_stats ieee_stats;
+#ifdef CONFIG_B43_HWRNG
struct hwrng rng;
- u8 rng_initialized;
+ bool rng_initialized;
char rng_name[30 + 1];
+#endif /* CONFIG_B43_HWRNG */
/* The RF-kill button */
struct b43_rfkill rfkill;
@@ -776,8 +778,8 @@ struct b43_wldev {
/* Reason code of the last interrupt. */
u32 irq_reason;
u32 dma_reason[6];
- /* saved irq enable/disable state bitfield. */
- u32 irq_savedstate;
+ /* The currently active generic-interrupt mask. */
+ u32 irq_mask;
/* Link Quality calculation context. */
struct b43_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 79b685e300c..a97c6ff0f12 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -673,32 +673,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev)
b43_set_slot_time(dev, 20);
}
-/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
-{
- u32 old_mask;
-
- old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
-
- return old_mask;
-}
-
-/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
-{
- u32 old_mask;
-
- old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
-
- return old_mask;
-}
-
/* Synchronize IRQ top- and bottom-half.
* IRQs must be masked before calling this.
* This must not be called with the irq_lock held.
@@ -1593,7 +1567,7 @@ static void handle_irq_beacon(struct b43_wldev *dev)
/* This is the bottom half of the asynchronous beacon update. */
/* Ignore interrupt in the future. */
- dev->irq_savedstate &= ~B43_IRQ_BEACON;
+ dev->irq_mask &= ~B43_IRQ_BEACON;
cmd = b43_read32(dev, B43_MMIO_MACCMD);
beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
@@ -1602,7 +1576,7 @@ static void handle_irq_beacon(struct b43_wldev *dev)
/* Schedule interrupt manually, if busy. */
if (beacon0_valid && beacon1_valid) {
b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
- dev->irq_savedstate |= B43_IRQ_BEACON;
+ dev->irq_mask |= B43_IRQ_BEACON;
return;
}
@@ -1641,11 +1615,9 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
spin_lock_irq(&wl->irq_lock);
/* update beacon right away or defer to irq */
- dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
handle_irq_beacon(dev);
/* The handler might have updated the IRQ mask. */
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK,
- dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irq(&wl->irq_lock);
}
@@ -1879,7 +1851,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
if (reason & B43_IRQ_TX_OK)
handle_irq_transmit_status(dev);
- b43_interrupt_enable(dev, dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
@@ -1893,7 +1865,9 @@ static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+/* Unused ring
b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+*/
}
/* Interrupt handler top-half */
@@ -1903,18 +1877,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
struct b43_wldev *dev = dev_id;
u32 reason;
- if (!dev)
- return IRQ_NONE;
+ B43_WARN_ON(!dev);
spin_lock(&dev->wl->irq_lock);
- if (b43_status(dev) < B43_STAT_STARTED)
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED)) {
+ /* This can only happen on shared IRQ lines. */
goto out;
+ }
reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) /* shared IRQ */
goto out;
ret = IRQ_HANDLED;
- reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ reason &= dev->irq_mask;
if (!reason)
goto out;
@@ -1928,16 +1903,18 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
& 0x0001DC00;
dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
& 0x0000DC00;
+/* Unused ring
dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
& 0x0000DC00;
+*/
b43_interrupt_ack(dev, reason);
/* disable all IRQs. They are enabled again in the bottom half. */
- dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
/* save the reason code and call our bottom half. */
dev->irq_reason = reason;
tasklet_schedule(&dev->isr_tasklet);
- out:
+out:
mmiowb();
spin_unlock(&dev->wl->irq_lock);
@@ -2980,6 +2957,7 @@ static void b43_security_init(struct b43_wldev *dev)
b43_clear_keys(dev);
}
+#ifdef CONFIG_B43_HWRNG
static int b43_rng_read(struct hwrng *rng, u32 *data)
{
struct b43_wl *wl = (struct b43_wl *)rng->priv;
@@ -2995,17 +2973,21 @@ static int b43_rng_read(struct hwrng *rng, u32 *data)
return (sizeof(u16));
}
+#endif /* CONFIG_B43_HWRNG */
static void b43_rng_exit(struct b43_wl *wl)
{
+#ifdef CONFIG_B43_HWRNG
if (wl->rng_initialized)
hwrng_unregister(&wl->rng);
+#endif /* CONFIG_B43_HWRNG */
}
static int b43_rng_init(struct b43_wl *wl)
{
- int err;
+ int err = 0;
+#ifdef CONFIG_B43_HWRNG
snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
"%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
wl->rng.name = wl->rng_name;
@@ -3018,6 +3000,7 @@ static int b43_rng_init(struct b43_wl *wl)
b43err(wl, "Failed to register the random "
"number generator (%d)\n", err);
}
+#endif /* CONFIG_B43_HWRNG */
return err;
}
@@ -3793,7 +3776,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
* setting the status to INITIALIZED, as the interrupt handler
* won't care about IRQs then. */
spin_lock_irqsave(&wl->irq_lock, flags);
- dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_synchronize_irq(dev);
@@ -3834,7 +3817,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
/* Start data flow (TX/RX). */
b43_mac_enable(dev);
- b43_interrupt_enable(dev, dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
/* Start maintainance work */
b43_periodic_tasks_setup(dev);
@@ -3997,9 +3980,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
/* IRQ related flags */
dev->irq_reason = 0;
memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
- dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
+ dev->irq_mask = B43_IRQ_MASKTEMPLATE;
if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
- dev->irq_savedstate &= ~B43_IRQ_PHY_TXERR;
+ dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
dev->mac_suspended = 1;
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index afad4235869..9e1d00bc24d 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -139,7 +139,6 @@ void b43_rfkill_init(struct b43_wldev *dev)
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
rfk->rfkill->data = dev;
rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
- rfk->rfkill->user_claim_unsupported = 1;
rfk->poll_dev = input_allocate_polled_device();
if (!rfk->poll_dev) {
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
index aef2298d37a..d4f628a74bb 100644
--- a/drivers/net/wireless/b43legacy/Kconfig
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -3,7 +3,6 @@ config B43LEGACY
depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
select SSB
select FW_LOADER
- select HW_RANDOM
---help---
b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
@@ -51,6 +50,13 @@ config B43LEGACY_RFKILL
depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY)
default y
+# This config option automatically enables b43 HW-RNG support,
+# if the HW-RNG core is enabled.
+config B43LEGACY_HWRNG
+ bool
+ depends on B43LEGACY && (HW_RANDOM = y || HW_RANDOM = B43LEGACY)
+ default y
+
config B43LEGACY_DEBUG
bool "Broadcom 43xx-legacy debugging"
depends on B43LEGACY
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 97b0e06dfe2..da59ef02b6e 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -59,7 +59,8 @@
#define B43legacy_MMIO_XMITSTAT_1 0x174
#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
-
+#define B43legacy_MMIO_TSF_CFP_REP 0x188
+#define B43legacy_MMIO_TSF_CFP_START 0x18C
/* 32-bit DMA */
#define B43legacy_MMIO_DMA32_BASE0 0x200
#define B43legacy_MMIO_DMA32_BASE1 0x220
@@ -258,7 +259,6 @@
#define B43legacy_IRQ_ALL 0xFFFFFFFF
#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
- B43legacy_IRQ_BEACON | \
B43legacy_IRQ_TBTT_INDI | \
B43legacy_IRQ_ATIM_END | \
B43legacy_IRQ_PMQ | \
@@ -596,9 +596,11 @@ struct b43legacy_wl {
/* Stats about the wireless interface */
struct ieee80211_low_level_stats ieee_stats;
+#ifdef CONFIG_B43LEGACY_HWRNG
struct hwrng rng;
u8 rng_initialized;
char rng_name[30 + 1];
+#endif
/* The RF-kill button */
struct b43legacy_rfkill rfkill;
@@ -614,6 +616,8 @@ struct b43legacy_wl {
struct sk_buff *current_beacon;
bool beacon0_uploaded;
bool beacon1_uploaded;
+ bool beacon_templates_virgin; /* Never wrote the templates? */
+ struct work_struct beacon_update_trigger;
};
/* Pointers to the firmware data and meta information about it. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 879edc78671..ee202b4f77b 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -955,23 +955,54 @@ static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
size + sizeof(struct b43legacy_plcp_hdr6));
}
+/* Convert a b43legacy antenna number value to the PHY TX control value. */
+static u16 b43legacy_antenna_to_phyctl(int antenna)
+{
+ switch (antenna) {
+ case B43legacy_ANTENNA0:
+ return B43legacy_TX4_PHY_ANT0;
+ case B43legacy_ANTENNA1:
+ return B43legacy_TX4_PHY_ANT1;
+ }
+ return B43legacy_TX4_PHY_ANTLAST;
+}
+
static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
u16 ram_offset,
- u16 shm_size_offset, u8 rate)
+ u16 shm_size_offset)
{
unsigned int i, len, variable_len;
const struct ieee80211_mgmt *bcn;
const u8 *ie;
bool tim_found = 0;
+ unsigned int rate;
+ u16 ctl;
+ int antenna;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
len = min((size_t)dev->wl->current_beacon->len,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset,
shm_size_offset, rate);
+ /* Write the PHY TX control parameters. */
+ antenna = B43legacy_ANTENNA_DEFAULT;
+ antenna = b43legacy_antenna_to_phyctl(antenna);
+ ctl = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL);
+ /* We can't send beacons with short preamble. Would get PHY errors. */
+ ctl &= ~B43legacy_TX4_PHY_SHORTPRMBL;
+ ctl &= ~B43legacy_TX4_PHY_ANT;
+ ctl &= ~B43legacy_TX4_PHY_ENC;
+ ctl |= antenna;
+ ctl |= B43legacy_TX4_PHY_ENC_CCK;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL, ctl);
+
/* Find the position of the TIM and the DTIM_period value
* and write them to SHM. */
ie = bcn->u.beacon.variable;
@@ -1013,7 +1044,8 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
b43legacywarn(dev->wl, "Did not find a valid TIM IE in the "
"beacon template packet. AP or IBSS operation "
"may be broken.\n");
- }
+ } else
+ b43legacydbg(dev->wl, "Updated beacon template\n");
}
static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
@@ -1025,7 +1057,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
__le16 dur;
plcp.data = 0;
- b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate);
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
dur = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->vif,
size,
@@ -1129,10 +1161,104 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
b43legacy_write_template_common(dev, probe_resp_data,
size, ram_offset,
- shm_size_offset, rate->bitrate);
+ shm_size_offset, rate->hw_value);
kfree(probe_resp_data);
}
+static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+
+ if (wl->beacon0_uploaded)
+ return;
+ b43legacy_write_beacon_template(dev, 0x68, 0x18);
+ /* FIXME: Probe resp upload doesn't really belong here,
+ * but we don't use that feature anyway. */
+ b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+ &__b43legacy_ratetable[3]);
+ wl->beacon0_uploaded = 1;
+}
+
+static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+
+ if (wl->beacon1_uploaded)
+ return;
+ b43legacy_write_beacon_template(dev, 0x468, 0x1A);
+ wl->beacon1_uploaded = 1;
+}
+
+static void handle_irq_beacon(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ u32 cmd, beacon0_valid, beacon1_valid;
+
+ if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
+ return;
+
+ /* This is the bottom half of the asynchronous beacon update. */
+
+ /* Ignore interrupt in the future. */
+ dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+
+ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
+ beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID);
+
+ /* Schedule interrupt manually, if busy. */
+ if (beacon0_valid && beacon1_valid) {
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON);
+ dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+ return;
+ }
+
+ if (unlikely(wl->beacon_templates_virgin)) {
+ /* We never uploaded a beacon before.
+ * Upload both templates now, but only mark one valid. */
+ wl->beacon_templates_virgin = 0;
+ b43legacy_upload_beacon0(dev);
+ b43legacy_upload_beacon1(dev);
+ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ cmd |= B43legacy_MACCMD_BEACON0_VALID;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
+ } else {
+ if (!beacon0_valid) {
+ b43legacy_upload_beacon0(dev);
+ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ cmd |= B43legacy_MACCMD_BEACON0_VALID;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
+ } else if (!beacon1_valid) {
+ b43legacy_upload_beacon1(dev);
+ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ cmd |= B43legacy_MACCMD_BEACON1_VALID;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
+ }
+ }
+}
+
+static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
+{
+ struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
+ beacon_update_trigger);
+ struct b43legacy_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
+ spin_lock_irq(&wl->irq_lock);
+ /* update beacon right away or defer to irq */
+ dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ handle_irq_beacon(dev);
+ /* The handler might have updated the IRQ mask. */
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
+ dev->irq_savedstate);
+ mmiowb();
+ spin_unlock_irq(&wl->irq_lock);
+ }
+ mutex_unlock(&wl->mutex);
+}
+
/* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */
static void b43legacy_update_templates(struct b43legacy_wl *wl)
@@ -1156,54 +1282,24 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
+ queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
}
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
u16 beacon_int)
{
b43legacy_time_lock(dev);
- if (dev->dev->id.revision >= 3)
- b43legacy_write32(dev, 0x188, (beacon_int << 16));
- else {
+ if (dev->dev->id.revision >= 3) {
+ b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_REP,
+ (beacon_int << 16));
+ b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_START,
+ (beacon_int << 10));
+ } else {
b43legacy_write16(dev, 0x606, (beacon_int >> 6));
b43legacy_write16(dev, 0x610, beacon_int);
}
b43legacy_time_unlock(dev);
-}
-
-static void handle_irq_beacon(struct b43legacy_wldev *dev)
-{
- struct b43legacy_wl *wl = dev->wl;
- u32 cmd;
-
- if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
- return;
-
- /* This is the bottom half of the asynchronous beacon update. */
-
- cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
- if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) {
- if (!wl->beacon0_uploaded) {
- b43legacy_write_beacon_template(dev, 0x68,
- B43legacy_SHM_SH_BTL0,
- B43legacy_CCK_RATE_1MB);
- b43legacy_write_probe_resp_template(dev, 0x268,
- B43legacy_SHM_SH_PRTLEN,
- &__b43legacy_ratetable[3]);
- wl->beacon0_uploaded = 1;
- }
- cmd |= B43legacy_MACCMD_BEACON0_VALID;
- }
- if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) {
- if (!wl->beacon1_uploaded) {
- b43legacy_write_beacon_template(dev, 0x468,
- B43legacy_SHM_SH_BTL1,
- B43legacy_CCK_RATE_1MB);
- wl->beacon1_uploaded = 1;
- }
- cmd |= B43legacy_MACCMD_BEACON1_VALID;
- }
- b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
+ b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
}
static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
@@ -2297,6 +2393,7 @@ static void b43legacy_security_init(struct b43legacy_wldev *dev)
dev->max_nr_keys - 8);
}
+#ifdef CONFIG_B43LEGACY_HWRNG
static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
{
struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
@@ -2312,17 +2409,21 @@ static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
return (sizeof(u16));
}
+#endif
static void b43legacy_rng_exit(struct b43legacy_wl *wl)
{
+#ifdef CONFIG_B43LEGACY_HWRNG
if (wl->rng_initialized)
hwrng_unregister(&wl->rng);
+#endif
}
static int b43legacy_rng_init(struct b43legacy_wl *wl)
{
- int err;
+ int err = 0;
+#ifdef CONFIG_B43LEGACY_HWRNG
snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
"%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
wl->rng.name = wl->rng_name;
@@ -2336,6 +2437,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
"number generator (%d)\n", err);
}
+#endif
return err;
}
@@ -3392,6 +3494,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
memset(wl->bssid, 0, ETH_ALEN);
memset(wl->mac_addr, 0, ETH_ALEN);
wl->filter_flags = 0;
+ wl->beacon0_uploaded = 0;
+ wl->beacon1_uploaded = 0;
+ wl->beacon_templates_virgin = 1;
mutex_lock(&wl->mutex);
@@ -3429,6 +3534,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
struct b43legacy_wldev *dev = wl->current_dev;
b43legacy_rfkill_exit(dev);
+ cancel_work_sync(&(wl->beacon_update_trigger));
mutex_lock(&wl->mutex);
if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
@@ -3760,6 +3866,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
spin_lock_init(&wl->leds_lock);
mutex_init(&wl->mutex);
INIT_LIST_HEAD(&wl->devlist);
+ INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
ssb_set_devtypedata(dev, wl);
b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index b32bf6a94f1..4b0c7d27a51 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -142,7 +142,6 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
rfk->rfkill->data = dev;
rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
- rfk->rfkill->user_claim_unsupported = 1;
rfk->poll_dev = input_allocate_polled_device();
if (!rfk->poll_dev) {
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 12fca99f757..b8e39dd06e9 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -274,7 +274,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
/* PHY TX Control word */
if (rate_ofdm)
- phy_ctl |= B43legacy_TX4_PHY_OFDM;
+ phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM;
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
switch (info->antenna_sel_tx) {
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 62e09d02788..91633087a20 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -67,7 +67,9 @@ struct b43legacy_txhdr_fw3 {
#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
/* PHY TX control word */
-#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
+#define B43legacy_TX4_PHY_ENC 0x0003 /* Data frame encoding */
+#define B43legacy_TX4_PHY_ENC_CCK 0x0000 /* CCK */
+#define B43legacy_TX4_PHY_ENC_OFDM 0x0001 /* Data frame rate type */
#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index cbf15d70320..0e5d51086a4 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -435,7 +435,7 @@ static int prism2_plx_probe(struct pci_dev *pdev,
unsigned long pccard_attr_mem;
unsigned int pccard_attr_len;
void __iomem *attr_mem = NULL;
- unsigned int cor_offset, cor_index;
+ unsigned int cor_offset = 0, cor_index = 0;
u32 reg;
local_info_t *local = NULL;
struct net_device *dev = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index af6b9d44477..f63a9c5ba26 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -719,7 +719,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
hdr->addr1);
sta_id = iwl3945_add_station(priv,
- hdr->addr1, 0, CMD_ASYNC);
+ hdr->addr1, 0, CMD_ASYNC, NULL);
}
if (sta_id != IWL_INVALID_STATION)
rs_sta->ibss_sta_added = 1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 527525cc091..41f1d66cfeb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1964,6 +1964,194 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
return 0;
}
+static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res = NULL;
+ struct iwl3945_rxon_assoc_cmd rxon_assoc;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_RXON_ASSOC,
+ .len = sizeof(rxon_assoc),
+ .meta.flags = CMD_WANT_SKB,
+ .data = &rxon_assoc,
+ };
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+/**
+ * iwl3945_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is committed to the hardware and
+ * the active_rxon structure is updated with the new data. This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl3945_commit_rxon(struct iwl_priv *priv)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
+ int rc = 0;
+ bool new_assoc =
+ !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+
+ if (!iwl_is_alive(priv))
+ return -1;
+
+ /* always get timestamp with Rx frame */
+ staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK;
+
+ /* select antenna */
+ staging_rxon->flags &=
+ ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
+ staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
+
+ rc = iwl_check_rxon_cmd(priv);
+ if (rc) {
+ IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /* If we don't need to send a full RXON, we can use
+ * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
+ * and other flags for the current radio configuration. */
+ if (!iwl_full_rxon_required(priv)) {
+ rc = iwl_send_rxon_assoc(priv);
+ if (rc) {
+ IWL_ERR(priv, "Error setting RXON_ASSOC "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
+
+ return 0;
+ }
+
+ /* If we are currently associated and the new config requires
+ * an RXON_ASSOC and the new config wants the associated mask enabled,
+ * we must clear the associated from the active configuration
+ * before we apply the new config */
+ if (iwl_is_associated(priv) && new_assoc) {
+ IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ /*
+ * reserved4 and 5 could have been filled by the iwlcore code.
+ * Let's clear them before pushing to the 3945.
+ */
+ active_rxon->reserved4 = 0;
+ active_rxon->reserved5 = 0;
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl3945_rxon_cmd),
+ &priv->active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (rc) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERR(priv, "Error clearing ASSOC_MSK on current "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+ }
+
+ IWL_DEBUG_INFO(priv, "Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %pM\n",
+ (new_assoc ? "" : "out"),
+ le16_to_cpu(staging_rxon->channel),
+ staging_rxon->bssid_addr);
+
+ /*
+ * reserved4 and 5 could have been filled by the iwlcore code.
+ * Let's clear them before pushing to the 3945.
+ */
+ staging_rxon->reserved4 = 0;
+ staging_rxon->reserved5 = 0;
+
+ iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+
+ /* Apply the new configuration */
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl3945_rxon_cmd),
+ staging_rxon);
+ if (rc) {
+ IWL_ERR(priv, "Error setting new configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
+
+ priv->cfg->ops->smgmt->clear_station_table(priv);
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ rc = priv->cfg->ops->lib->send_tx_power(priv);
+ if (rc) {
+ IWL_ERR(priv, "Error setting Tx power (%d).\n", rc);
+ return rc;
+ }
+
+ /* Add the broadcast address so we can send broadcast frames */
+ if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) ==
+ IWL_INVALID_STATION) {
+ IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
+ return -EIO;
+ }
+
+ /* If we have set the ASSOC_MSK and we are in BSS mode then
+ * add the IWL_AP_ID to the station rate table */
+ if (iwl_is_associated(priv) &&
+ (priv->iw_mode == NL80211_IFTYPE_STATION))
+ if (priv->cfg->ops->smgmt->add_station(priv,
+ priv->active_rxon.bssid_addr, 1, 0, NULL)
+ == IWL_INVALID_STATION) {
+ IWL_ERR(priv, "Error adding AP address for transmit\n");
+ return -EIO;
+ }
+
+ /* Init the hardware's rate fallback order based on the band */
+ rc = iwl3945_init_hw_rate_table(priv);
+ if (rc) {
+ IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/* will add 3945 channel switch cmd handling later */
int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
@@ -2729,6 +2917,11 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}
+static struct iwl_hcmd_ops iwl3945_hcmd = {
+ .rxon_assoc = iwl3945_send_rxon_assoc,
+ .commit_rxon = iwl3945_commit_rxon,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2758,6 +2951,17 @@ static struct iwl_lib_ops iwl3945_lib = {
},
.send_tx_power = iwl3945_send_tx_power,
.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
+ .post_associate = iwl3945_post_associate,
+ .config_ap = iwl3945_config_ap,
+};
+
+static struct iwl_station_mgmt_ops iwl3945_station_mgmt = {
+ .add_station = iwl3945_add_station,
+#if 0
+ .remove_station = iwl3945_remove_station,
+#endif
+ .find_station = iwl3945_hw_find_station,
+ .clear_station_table = iwl3945_clear_stations_table,
};
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
@@ -2767,7 +2971,9 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
static struct iwl_ops iwl3945_ops = {
.lib = &iwl3945_lib,
+ .hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
+ .smgmt = &iwl3945_station_mgmt,
};
static struct iwl_cfg iwl3945_bg_cfg = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 55188844657..da87528f355 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -162,7 +162,6 @@ struct iwl3945_frame {
#define STATUS_TEMPERATURE 8
#define STATUS_GEO_CONFIGURED 9
#define STATUS_EXIT_PENDING 10
-#define STATUS_IN_SUSPEND 11
#define STATUS_STATISTICS 12
#define STATUS_SCANNING 13
#define STATUS_SCAN_ABORTING 14
@@ -207,7 +206,8 @@ struct iwl3945_addsta_cmd;
extern int iwl3945_send_add_station(struct iwl_priv *priv,
struct iwl3945_addsta_cmd *sta, u8 flags);
extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid,
- int is_ap, u8 flags);
+ int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
+extern void iwl3945_clear_stations_table(struct iwl_priv *priv);
extern int iwl3945_power_init_handle(struct iwl_priv *priv);
extern int iwl3945_eeprom_init(struct iwl_priv *priv);
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
@@ -278,6 +278,8 @@ extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
extern void iwl3945_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+extern void iwl3945_post_associate(struct iwl_priv *priv);
+extern void iwl3945_config_ap(struct iwl_priv *priv);
/**
* iwl3945_hw_find_station - Find station id for a given BSSID
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 847a6220c5e..a98ff4ead72 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2268,9 +2268,17 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}
+static struct iwl_station_mgmt_ops iwl4965_station_mgmt = {
+ .add_station = iwl_add_station_flags,
+ .remove_station = iwl_remove_station,
+ .find_station = iwl_find_station,
+ .clear_station_table = iwl_clear_stations_table,
+};
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
+ .commit_rxon = iwl_commit_rxon,
+ .set_rxon_chain = iwl_set_rxon_chain,
};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
@@ -2324,12 +2332,15 @@ static struct iwl_lib_ops iwl4965_lib = {
.send_tx_power = iwl4965_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.temperature = iwl4965_temperature_calib,
+ .post_associate = iwl_post_associate,
+ .config_ap = iwl_config_ap,
};
static struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
+ .smgmt = &iwl4965_station_mgmt,
};
struct iwl_cfg iwl4965_agn_cfg = {
@@ -2350,8 +2361,6 @@ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index e5ca2511a81..d731a836e6c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -678,7 +678,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
goto restart;
}
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
IWL_WARN(priv,
@@ -1472,8 +1472,17 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+struct iwl_station_mgmt_ops iwl5000_station_mgmt = {
+ .add_station = iwl_add_station_flags,
+ .remove_station = iwl_remove_station,
+ .find_station = iwl_find_station,
+ .clear_station_table = iwl_clear_stations_table,
+};
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
+ .commit_rxon = iwl_commit_rxon,
+ .set_rxon_chain = iwl_set_rxon_chain,
};
struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
@@ -1527,12 +1536,15 @@ struct iwl_lib_ops iwl5000_lib = {
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
},
+ .post_associate = iwl_post_associate,
+ .config_ap = iwl_config_ap,
};
struct iwl_ops iwl5000_ops = {
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .smgmt = &iwl5000_station_mgmt,
};
struct iwl_mod_params iwl50_mod_params = {
@@ -1643,9 +1655,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
-module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
-MODULE_PARM_DESC(disable50,
- "manually disable the 50XX radio (default 0 [radio on])");
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index edfa5e149f7..ee271d7f612 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -72,6 +72,7 @@ static struct iwl_ops iwl6000_ops = {
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
+ .smgmt = &iwl5000_station_mgmt,
};
struct iwl_cfg iwl6000_2ag_cfg = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cab7842a73a..3504279c758 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -52,7 +52,7 @@
/* max allowed rate miss before sync LQ cmd */
#define IWL_MISSED_RATE_MAX 15
/* max time to accum history 2 seconds */
-#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ)
+#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ)
static u8 rs_ht_to_legacy[] = {
IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
@@ -135,7 +135,7 @@ struct iwl_lq_sta {
u32 table_count;
u32 total_failed; /* total failed frames, any/all rates */
u32 total_success; /* total successful frames, any/all rates */
- u32 flush_timer; /* time staying in mode before new search */
+ u64 flush_timer; /* time staying in mode before new search */
u8 action_counter; /* # mode-switch actions tried */
u8 is_green;
@@ -167,6 +167,8 @@ struct iwl_lq_sta {
/* used to be in sta_info */
int last_txrate_idx;
+ /* last tx rate_n_flags */
+ u32 last_rate_n_flags;
};
static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -191,7 +193,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
* 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
* "G" is the only table that supports CCK (the first 4 rates).
*/
-/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/
+
static s32 expected_tpt_A[IWL_RATE_COUNT] = {
0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
};
@@ -208,11 +210,11 @@ static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
};
-static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
+static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = {
0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
};
-static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
+static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = {
0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
};
@@ -224,14 +226,48 @@ static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
};
-static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
+static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = {
0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
};
-static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
+static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
};
+/* Expected throughput metric MIMO3 */
+static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268
+};
+
+static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
+};
+
+static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297
+};
+
+static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300
+};
+
+/* mbps, mcs */
+const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+ {"1", ""},
+ {"2", ""},
+ {"5.5", ""},
+ {"11", ""},
+ {"6", "BPSK 1/2"},
+ {"9", "BPSK 1/2"},
+ {"12", "QPSK 1/2"},
+ {"18", "QPSK 3/4"},
+ {"24", "16QAM 1/2"},
+ {"36", "16QAM 3/4"},
+ {"48", "64QAM 2/3"},
+ {"54", "64QAM 3/4"},
+ {"60", "64QAM 5/6"}
+};
+
static inline u8 rs_extract_rate(u32 rate_n_flags)
{
return (u8)(rate_n_flags & 0xFF);
@@ -902,6 +938,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
* else look up the rate that was, finally, successful.
*/
tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
+ lq_sta->last_rate_n_flags = tx_rate;
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
/* Update frame history window with "success" if Tx got ACKed ... */
@@ -988,6 +1025,7 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
lq_sta->table_count = 0;
lq_sta->total_failed = 0;
lq_sta->total_success = 0;
+ lq_sta->flush_timer = jiffies;
}
/*
@@ -1011,17 +1049,26 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
tbl->expected_tpt = expected_tpt_siso20MHzSGI;
else
tbl->expected_tpt = expected_tpt_siso20MHz;
-
- } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */
+ } else if (is_mimo2(tbl->lq_type)) {
+ if (tbl->is_fat && !lq_sta->is_dup)
+ if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo2_40MHz;
+ else if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo2_20MHz;
+ } else if (is_mimo3(tbl->lq_type)) {
if (tbl->is_fat && !lq_sta->is_dup)
if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
+ tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
else
- tbl->expected_tpt = expected_tpt_mimo40MHz;
+ tbl->expected_tpt = expected_tpt_mimo3_40MHz;
else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
+ tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI;
else
- tbl->expected_tpt = expected_tpt_mimo20MHz;
+ tbl->expected_tpt = expected_tpt_mimo3_20MHz;
} else
tbl->expected_tpt = expected_tpt_G;
}
@@ -1130,7 +1177,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
}
/*
- * Set up search table for MIMO
+ * Set up search table for MIMO2
*/
static int rs_switch_to_mimo2(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta,
@@ -1183,7 +1230,73 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+
+ IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate, is_green);
+ return 0;
+}
+
+/*
+ * Set up search table for MIMO3
+ */
+static int rs_switch_to_mimo3(struct iwl_priv *priv,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_conf *conf,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ u16 rate_mask;
+ s32 rate;
+ s8 is_green = lq_sta->is_green;
+
+ if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+ return -1;
+
+ if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+ == WLAN_HT_CAP_SM_PS_STATIC)
+ return -1;
+
+ /* Need both Tx chains/antennas to support MIMO */
+ if (priv->hw_params.tx_chains_num < 3)
+ return -1;
+
+ IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
+
+ tbl->lq_type = LQ_MIMO3;
+ tbl->is_dup = lq_sta->is_dup;
+ tbl->action = 0;
+ rate_mask = lq_sta->active_mimo3_rate;
+
+ if (priv->current_ht_config.supported_chan_width
+ == IWL_CHANNEL_WIDTH_40MHZ)
+ tbl->is_fat = 1;
+ else
+ tbl->is_fat = 0;
+
+ /* FIXME: - don't toggle SGI here
+ if (tbl->is_fat) {
+ if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ */
+
+ rs_set_expected_tpt_table(lq_sta, tbl);
+
+ rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+ IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
+ rate, rate_mask);
if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
rate, rate_mask);
@@ -1342,9 +1455,29 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
goto out;
}
break;
+
+ case IWL_LEGACY_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
+
+ /* Set up search table to try MIMO3 */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+ search_tbl, index);
+ if (!ret) {
+ lq_sta->action_counter = 0;
+ goto out;
+ }
+ break;
}
tbl->action++;
- if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
if (tbl->action == start_action)
@@ -1357,7 +1490,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
out:
lq_sta->search_better_tbl = 1;
tbl->action++;
- if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC)
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
return 0;
@@ -1457,9 +1590,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
rate_n_flags_from_tbl(priv, search_tbl,
index, is_green);
goto out;
+ case IWL_SISO_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+ break;
}
tbl->action++;
- if (tbl->action > IWL_SISO_SWITCH_GI)
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
if (tbl->action == start_action)
@@ -1471,15 +1618,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
out:
lq_sta->search_better_tbl = 1;
tbl->action++;
- if (tbl->action > IWL_SISO_SWITCH_GI)
+ if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
return 0;
}
/*
- * Try to switch to new modulation mode from MIMO
+ * Try to switch to new modulation mode from MIMO2
*/
-static int rs_move_mimo_to_other(struct iwl_priv *priv,
+static int rs_move_mimo2_to_other(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
struct ieee80211_sta *sta, int index)
@@ -1501,7 +1648,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
switch (tbl->action) {
case IWL_MIMO2_SWITCH_ANTENNA1:
case IWL_MIMO2_SWITCH_ANTENNA2:
- IWL_DEBUG_RATE(priv, "LQ: MIMO toggle Antennas\n");
+ IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
if (tx_chains_num <= 2)
break;
@@ -1549,9 +1696,9 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
HT_SHORT_GI_40MHZ))
break;
- IWL_DEBUG_RATE(priv, "LQ: MIMO toggle SGI/NGI\n");
+ IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
- /* Set up new search table for MIMO */
+ /* Set up new search table for MIMO2 */
memcpy(search_tbl, tbl, sz);
search_tbl->is_SGI = !tbl->is_SGI;
rs_set_expected_tpt_table(lq_sta, search_tbl);
@@ -1571,9 +1718,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
index, is_green);
goto out;
+ case IWL_MIMO2_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
}
tbl->action++;
- if (tbl->action > IWL_MIMO2_SWITCH_GI)
+ if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
if (tbl->action == start_action)
@@ -1584,13 +1746,150 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
out:
lq_sta->search_better_tbl = 1;
tbl->action++;
- if (tbl->action > IWL_MIMO2_SWITCH_GI)
+ if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
return 0;
}
/*
+ * Try to switch to new modulation mode from MIMO3
+ */
+static int rs_move_mimo3_to_other(struct iwl_priv *priv,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_conf *conf,
+ struct ieee80211_sta *sta, int index)
+{
+ s8 is_green = lq_sta->is_green;
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+ u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+ u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ int ret;
+
+ for (;;) {
+ lq_sta->action_counter++;
+ switch (tbl->action) {
+ case IWL_MIMO3_SWITCH_ANTENNA1:
+ case IWL_MIMO3_SWITCH_ANTENNA2:
+ IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
+
+ if (tx_chains_num <= 3)
+ break;
+
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate, search_tbl))
+ goto out;
+ break;
+ case IWL_MIMO3_SWITCH_SISO_A:
+ case IWL_MIMO3_SWITCH_SISO_B:
+ case IWL_MIMO3_SWITCH_SISO_C:
+ IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
+
+ /* Set up new search table for SISO */
+ memcpy(search_tbl, tbl, sz);
+
+ if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
+ search_tbl->ant_type = ANT_A;
+ else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+ search_tbl->ant_type = ANT_B;
+ else
+ search_tbl->ant_type = ANT_C;
+
+ if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+
+ case IWL_MIMO3_SWITCH_MIMO2_AB:
+ case IWL_MIMO3_SWITCH_MIMO2_AC:
+ case IWL_MIMO3_SWITCH_MIMO2_BC:
+ IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
+
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
+ search_tbl->ant_type = ANT_AB;
+ else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
+ search_tbl->ant_type = ANT_AC;
+ else
+ search_tbl->ant_type = ANT_BC;
+
+ if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+
+ case IWL_MIMO3_SWITCH_GI:
+ if (!tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_20MHZ))
+ break;
+ if (tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_40MHZ))
+ break;
+
+ IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
+
+ /* Set up new search table for MIMO */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = !tbl->is_SGI;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+ /*
+ * If active table already uses the fastest possible
+ * modulation (dual stream with short guard interval),
+ * and it's working well, there's no need to look
+ * for a better type of modulation!
+ */
+ if (tbl->is_SGI) {
+ s32 tpt = lq_sta->last_tpt / 100;
+ if (tpt >= search_tbl->expected_tpt[index])
+ break;
+ }
+ search_tbl->current_rate =
+ rate_n_flags_from_tbl(priv, search_tbl,
+ index, is_green);
+ goto out;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_MIMO3_SWITCH_GI)
+ tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ search_tbl->lq_type = LQ_NONE;
+ return 0;
+ out:
+ lq_sta->search_better_tbl = 1;
+ tbl->action++;
+ if (tbl->action > IWL_MIMO3_SWITCH_GI)
+ tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+ return 0;
+
+}
+
+/*
* Check whether we should continue using same modulation mode, or
* begin search for a new mode, based on:
* 1) # tx successes or failures while using this mode
@@ -1616,8 +1915,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
/* Elapsed time using current modulation mode */
if (lq_sta->flush_timer)
flush_interval_passed =
- time_after(jiffies,
- (unsigned long)(lq_sta->flush_timer +
+ time_after(jiffies,
+ (unsigned long)(lq_sta->flush_timer +
IWL_RATE_SCALE_FLUSH_INTVL));
/*
@@ -1951,6 +2250,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
update_lq = 1;
index = low;
}
+
break;
case 1:
/* Increase starting rate, update uCode's rate table */
@@ -1997,8 +2297,10 @@ lq_update:
rs_move_legacy_other(priv, lq_sta, conf, sta, index);
else if (is_siso(tbl->lq_type))
rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
+ else if (is_mimo2(tbl->lq_type))
+ rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
else
- rs_move_mimo_to_other(priv, lq_sta, conf, sta, index);
+ rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
/* If new "search" mode was selected, set up in uCode table */
if (lq_sta->search_better_tbl) {
@@ -2014,8 +2316,11 @@ lq_update:
tbl->current_rate, index);
rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
- }
+ } else
+ done_search = 1;
+ }
+ if (done_search && !lq_sta->stay_in_tbl) {
/* If the "active" (non-search) mode was legacy,
* and we've tried switching antennas,
* but we haven't been able to try HT modes (not available),
@@ -2050,17 +2355,6 @@ lq_update:
lq_sta->action_counter = 0;
rs_set_stay_in_table(priv, 0, lq_sta);
}
-
- /*
- * Else, don't search for a new modulation mode.
- * Put new timestamp in stay-in-modulation-mode flush timer if:
- * 1) Not changing rates right now
- * 2) Not just finishing up a search
- * 3) flush timer is empty
- */
- } else {
- if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer))
- lq_sta->flush_timer = jiffies;
}
out:
@@ -2173,13 +2467,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) {
- u8 sta_id = iwl_find_station(priv, hdr->addr1);
+ u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
+ hdr->addr1);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
hdr->addr1);
- sta_id = iwl_add_station_flags(priv, hdr->addr1,
- 0, CMD_ASYNC, NULL);
+ sta_id = priv->cfg->ops->smgmt->add_station(priv,
+ hdr->addr1, 0,
+ CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
lq_sta->lq.sta_id = sta_id;
@@ -2246,15 +2542,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->ibss_sta_added = 0;
if (priv->iw_mode == NL80211_IFTYPE_AP) {
- u8 sta_id = iwl_find_station(priv, sta->addr);
+ u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
+ sta->addr);
/* for IBSS the call are from tasklet */
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
- sta_id = iwl_add_station_flags(priv, sta->addr,
- 0, CMD_ASYNC, NULL);
+ sta_id = priv->cfg->ops->smgmt->add_station(priv,
+ sta->addr, 0,
+ CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
lq_sta->lq.sta_id = sta_id;
@@ -2539,6 +2837,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
char *buff;
int desc = 0;
int i = 0;
+ int index = 0;
ssize_t ret;
struct iwl_lq_sta *lq_sta = file->private_data;
@@ -2570,6 +2869,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(tbl->is_fat) ? "40MHz" : "20MHz");
desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
}
+ desc += sprintf(buff+desc, "last tx rate=0x%X\n",
+ lq_sta->last_rate_n_flags);
desc += sprintf(buff+desc, "general:"
"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
lq_sta->lq.general_params.flags,
@@ -2590,10 +2891,19 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->lq.general_params.start_rate_index[2],
lq_sta->lq.general_params.start_rate_index[3]);
-
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
- desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
- i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ index = iwl_hwrate_to_plcp_idx(
+ le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
+ if (is_legacy(tbl->lq_type)) {
+ desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
+ i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+ iwl_rate_mcs[index].mbps);
+ } else {
+ desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
+ i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+ iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
+ }
+ }
ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
kfree(buff);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index ab59acc405d..f875136bc5d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -241,6 +241,7 @@ enum {
#define IWL_LEGACY_SWITCH_MIMO2_AB 3
#define IWL_LEGACY_SWITCH_MIMO2_AC 4
#define IWL_LEGACY_SWITCH_MIMO2_BC 5
+#define IWL_LEGACY_SWITCH_MIMO3_ABC 6
/* possible actions when in siso mode */
#define IWL_SISO_SWITCH_ANTENNA1 0
@@ -249,6 +250,8 @@ enum {
#define IWL_SISO_SWITCH_MIMO2_AC 3
#define IWL_SISO_SWITCH_MIMO2_BC 4
#define IWL_SISO_SWITCH_GI 5
+#define IWL_SISO_SWITCH_MIMO3_ABC 6
+
/* possible actions when in mimo mode */
#define IWL_MIMO2_SWITCH_ANTENNA1 0
@@ -257,6 +260,21 @@ enum {
#define IWL_MIMO2_SWITCH_SISO_B 3
#define IWL_MIMO2_SWITCH_SISO_C 4
#define IWL_MIMO2_SWITCH_GI 5
+#define IWL_MIMO2_SWITCH_MIMO3_ABC 6
+
+
+/* possible actions when in mimo3 mode */
+#define IWL_MIMO3_SWITCH_ANTENNA1 0
+#define IWL_MIMO3_SWITCH_ANTENNA2 1
+#define IWL_MIMO3_SWITCH_SISO_A 2
+#define IWL_MIMO3_SWITCH_SISO_B 3
+#define IWL_MIMO3_SWITCH_SISO_C 4
+#define IWL_MIMO3_SWITCH_MIMO2_AB 5
+#define IWL_MIMO3_SWITCH_MIMO2_AC 6
+#define IWL_MIMO3_SWITCH_MIMO2_BC 7
+#define IWL_MIMO3_SWITCH_GI 8
+
+
/*FIXME:RS:add possible actions for MIMO3*/
@@ -307,6 +325,13 @@ enum iwl_table_type {
#define ANT_BC (ANT_B | ANT_C)
#define ANT_ABC (ANT_AB | ANT_C)
+#define IWL_MAX_MCS_DISPLAY_SIZE 12
+
+struct iwl_rate_mcs_info {
+ char mbps[IWL_MAX_MCS_DISPLAY_SIZE];
+ char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
+};
+
static inline u8 num_of_ant(u8 mask)
{
return !!((mask) & ANT_A) +
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1ef4192207a..277dfc57fde 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -102,7 +102,7 @@ MODULE_ALIAS("iwl4965");
* function correctly transitions out of the RXON_ASSOC_MSK state if
* a HW tune is required based on the RXON structure changes.
*/
-static int iwl_commit_rxon(struct iwl_priv *priv)
+int iwl_commit_rxon(struct iwl_priv *priv)
{
/* cast away the const for active_rxon in this function */
struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
@@ -188,7 +188,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
}
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
if (!priv->error_recovering)
priv->start_calib = 0;
@@ -246,8 +246,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
void iwl_update_chain_flags(struct iwl_priv *priv)
{
- iwl_set_rxon_chain(priv);
- iwl_commit_rxon(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ iwlcore_commit_rxon(priv);
}
static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -531,76 +532,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
*
******************************************************************************/
-static void iwl_ht_conf(struct iwl_priv *priv,
- struct ieee80211_bss_conf *bss_conf)
-{
- struct ieee80211_sta_ht_cap *ht_conf;
- struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
- struct ieee80211_sta *sta;
-
- IWL_DEBUG_MAC80211(priv, "enter: \n");
-
- if (!iwl_conf->is_ht)
- return;
-
-
- /*
- * It is totally wrong to base global information on something
- * that is valid only when associated, alas, this driver works
- * that way and I don't know how to fix it.
- */
-
- rcu_read_lock();
- sta = ieee80211_find_sta(priv->hw, priv->bssid);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
- ht_conf = &sta->ht_cap;
-
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
- iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
- iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
-
- iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
- iwl_conf->max_amsdu_size =
- !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
-
- iwl_conf->supported_chan_width =
- !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
- /*
- * XXX: The HT configuration needs to be moved into iwl_mac_config()
- * to be done there correctly.
- */
-
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
- if (conf_is_ht40_minus(&priv->hw->conf))
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- else if (conf_is_ht40_plus(&priv->hw->conf))
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-
- /* If no above or below channel supplied disable FAT channel */
- if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
- iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
- iwl_conf->supported_chan_width = 0;
-
- iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
-
- memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
-
- iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
- iwl_conf->ht_protection =
- bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
- iwl_conf->non_GF_STA_present =
- !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
- rcu_read_unlock();
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
#define MAX_UCODE_BEACON_INTERVAL 4096
static u16 iwl_adjust_beacon_interval(u16 beacon_val)
@@ -657,30 +588,6 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
le16_to_cpu(priv->rxon_timing.atim_window));
}
-static int iwl_set_mode(struct iwl_priv *priv, int mode)
-{
- iwl_connection_init_rx_config(priv, mode);
- iwl_set_rxon_chain(priv);
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
- iwl_clear_stations_table(priv);
-
- /* dont commit rxon if rf-kill is on*/
- if (!iwl_is_ready_rf(priv))
- return -EAGAIN;
-
- cancel_delayed_work(&priv->scan_check);
- if (iwl_scan_cancel_timeout(priv, 100)) {
- IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
- IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
- return -EAGAIN;
- }
-
- iwl_commit_rxon(priv);
-
- return 0;
-}
-
/******************************************************************************
*
* Generic RX handler implementations
@@ -1002,6 +909,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r,
i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
} else {
/* No handling needed */
IWL_DEBUG_RX(priv,
@@ -1065,7 +973,7 @@ static void iwl_error_recovery(struct iwl_priv *priv)
memcpy(&priv->staging_rxon, &priv->recovery_rxon,
sizeof(priv->staging_rxon));
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
iwl_rxon_add_station(priv, priv->bssid, 1);
@@ -1123,6 +1031,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
+ priv->isr_stats.hw++;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_HW_ERR;
@@ -1135,13 +1044,17 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD)
+ if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
"the frame/frames.\n");
+ priv->isr_stats.sch++;
+ }
/* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE)
+ if (inta & CSR_INT_BIT_ALIVE) {
IWL_DEBUG_ISR(priv, "Alive interrupt\n");
+ priv->isr_stats.alive++;
+ }
}
#endif
/* Safely ignore these bits for debug checks below */
@@ -1157,6 +1070,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
+ priv->isr_stats.rfkill++;
+
/* driver only loads ucode once setting the interface up.
* the driver allows loading the ucode even if the radio
* is killed. Hence update the killswitch state here. The
@@ -1176,6 +1091,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Chip got too hot and stopped itself */
if (inta & CSR_INT_BIT_CT_KILL) {
IWL_ERR(priv, "Microcode CT kill error detected.\n");
+ priv->isr_stats.ctkill++;
handled |= CSR_INT_BIT_CT_KILL;
}
@@ -1183,6 +1099,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
if (inta & CSR_INT_BIT_SW_ERR) {
IWL_ERR(priv, "Microcode SW error detected. "
" Restarting 0x%X.\n", inta);
+ priv->isr_stats.sw++;
+ priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -1198,6 +1116,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
iwl_txq_update_write_ptr(priv, &priv->txq[4]);
iwl_txq_update_write_ptr(priv, &priv->txq[5]);
+ priv->isr_stats.wakeup++;
+
handled |= CSR_INT_BIT_WAKEUP;
}
@@ -1206,19 +1126,23 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
* notifications from uCode come through here*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
iwl_rx_handle(priv);
+ priv->isr_stats.rx++;
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
}
if (inta & CSR_INT_BIT_FH_TX) {
IWL_DEBUG_ISR(priv, "Tx interrupt\n");
+ priv->isr_stats.tx++;
handled |= CSR_INT_BIT_FH_TX;
/* FH finished to write, send event */
priv->ucode_write_complete = 1;
wake_up_interruptible(&priv->wait_command_queue);
}
- if (inta & ~handled)
+ if (inta & ~handled) {
IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+ priv->isr_stats.unhandled++;
+ }
if (inta & ~CSR_INI_SET_MASK) {
IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
@@ -1243,6 +1167,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
+
/******************************************************************************
*
* uCode download functions
@@ -1508,10 +1433,6 @@ static int iwl_read_ucode(struct iwl_priv *priv)
return ret;
}
-/* temporary */
-static int iwl_mac_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *skb);
-
/**
* iwl_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
@@ -1540,7 +1461,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
goto restart;
}
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
IWL_WARN(priv,
@@ -1568,7 +1489,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
} else {
/* Initialize our rx_config data */
iwl_connection_init_rx_config(priv, priv->iw_mode);
- iwl_set_rxon_chain(priv);
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
@@ -1578,7 +1502,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
iwl_reset_run_time_calib(priv);
/* Configure the adapter for unassociated operation */
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
@@ -1626,7 +1550,7 @@ static void __iwl_down(struct iwl_priv *priv)
iwl_leds_unregister(priv);
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
/* Unblock any waiting calls */
wake_up_interruptible_all(&priv->wait_command_queue);
@@ -1649,7 +1573,7 @@ static void __iwl_down(struct iwl_priv *priv)
ieee80211_stop_queues(priv->hw);
/* If we have not previously called iwl_init() then
- * clear all bits but the RF Kill and SUSPEND bits and return */
+ * clear all bits but the RF Kill bits and return */
if (!iwl_is_init(priv)) {
priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
STATUS_RF_KILL_HW |
@@ -1657,23 +1581,19 @@ static void __iwl_down(struct iwl_priv *priv)
STATUS_RF_KILL_SW |
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
- test_bit(STATUS_IN_SUSPEND, &priv->status) <<
- STATUS_IN_SUSPEND |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
goto exit;
}
- /* ...otherwise clear out all the status bits but the RF Kill and
- * SUSPEND bits and continue taking the NIC down. */
+ /* ...otherwise clear out all the status bits but the RF Kill
+ * bits and continue taking the NIC down. */
priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
- test_bit(STATUS_IN_SUSPEND, &priv->status) <<
- STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
STATUS_FW_ERROR |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
@@ -1698,7 +1618,7 @@ static void __iwl_down(struct iwl_priv *priv)
udelay(5);
/* FIXME: apm_ops.suspend(priv) */
- if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+ if (exit_pending)
priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv);
@@ -1781,7 +1701,7 @@ static int __iwl_up(struct iwl_priv *priv)
for (i = 0; i < MAX_HW_RESTARTS; i++) {
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
@@ -1910,7 +1830,7 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static void iwl_post_associate(struct iwl_priv *priv)
+void iwl_post_associate(struct iwl_priv *priv)
{
struct ieee80211_conf *conf = NULL;
int ret = 0;
@@ -1938,7 +1858,7 @@ static void iwl_post_associate(struct iwl_priv *priv)
conf = ieee80211_get_hw_conf(priv->hw);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
iwl_setup_rxon_timing(priv);
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
@@ -1951,7 +1871,9 @@ static void iwl_post_associate(struct iwl_priv *priv)
iwl_set_rxon_ht(priv, &priv->current_ht_config);
- iwl_set_rxon_chain(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
@@ -1973,7 +1895,7 @@ static void iwl_post_associate(struct iwl_priv *priv)
}
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
switch (priv->iw_mode) {
case NL80211_IFTYPE_STATION:
@@ -2059,9 +1981,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
IWL_DEBUG_INFO(priv, "Start UP work done.\n");
- if (test_bit(STATUS_IN_SUSPEND, &priv->status))
- return 0;
-
/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
@@ -2130,175 +2049,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int iwl_mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
-
- IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
-
- if (priv->vif) {
- IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
- return -EOPNOTSUPP;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->vif = conf->vif;
- priv->iw_mode = conf->type;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- mutex_lock(&priv->mutex);
-
- if (conf->mac_addr) {
- IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- }
-
- if (iwl_set_mode(priv, conf->type) == -EAGAIN)
- /* we are not ready, will run again when ready */
- set_bit(STATUS_MODE_PENDING, &priv->status);
-
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
-}
-
-/**
- * iwl_mac_config - mac80211 config callback
- *
- * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
- * be set inappropriately and the driver currently sets the hardware up to
- * use it whenever needed.
- */
-static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct iwl_priv *priv = hw->priv;
- const struct iwl_channel_info *ch_info;
- struct ieee80211_conf *conf = &hw->conf;
- unsigned long flags = 0;
- int ret = 0;
- u16 ch;
- int scan_active = 0;
-
- mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
- conf->channel->hw_value, changed);
-
- if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
- test_bit(STATUS_SCANNING, &priv->status))) {
- scan_active = 1;
- IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
- }
-
-
- /* during scanning mac80211 will delay channel setting until
- * scan finish with changed = 0
- */
- if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
- if (scan_active)
- goto set_ch_out;
-
- ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
- ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
- if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
- ret = -EINVAL;
- goto set_ch_out;
- }
-
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
- !is_channel_ibss(ch_info)) {
- IWL_ERR(priv, "channel %d in band %d not "
- "IBSS channel\n",
- conf->channel->hw_value, conf->channel->band);
- ret = -EINVAL;
- goto set_ch_out;
- }
-
- priv->current_ht_config.is_ht = conf_is_ht(conf);
-
- spin_lock_irqsave(&priv->lock, flags);
-
-
- /* if we are switching from ht to 2.4 clear flags
- * from any ht related info since 2.4 does not
- * support ht */
- if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
- priv->staging_rxon.flags = 0;
-
- iwl_set_rxon_channel(priv, conf->channel);
-
- iwl_set_flags_for_band(priv, conf->channel->band);
- spin_unlock_irqrestore(&priv->lock, flags);
- set_ch_out:
- /* The list of supported rates and rate mask can be different
- * for each band; since the band may have changed, reset
- * the rate mask to what mac80211 lists */
- iwl_set_rate(priv);
- }
-
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- if (conf->flags & IEEE80211_CONF_PS)
- ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3);
- else
- ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM);
- if (ret)
- IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
-
- }
-
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
- IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
- priv->tx_power_user_lmt, conf->power_level);
-
- iwl_set_tx_power(priv, conf->power_level, false);
- }
-
- /* call to ensure that 4965 rx_chain is set properly in monitor mode */
- iwl_set_rxon_chain(priv);
-
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- if (conf->radio_enabled &&
- iwl_radio_kill_sw_enable_radio(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - "
- "waiting for uCode\n");
- goto out;
- }
-
- if (!conf->radio_enabled)
- iwl_radio_kill_sw_disable_radio(priv);
- }
-
- if (!conf->radio_enabled) {
- IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
- goto out;
- }
-
- if (!iwl_is_ready(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- goto out;
- }
-
- if (scan_active)
- goto out;
-
- if (memcmp(&priv->active_rxon,
- &priv->staging_rxon, sizeof(priv->staging_rxon)))
- iwl_commit_rxon(priv);
- else
- IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n");
-
-
-out:
- IWL_DEBUG_MAC80211(priv, "leave\n");
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static void iwl_config_ap(struct iwl_priv *priv)
+void iwl_config_ap(struct iwl_priv *priv)
{
int ret = 0;
unsigned long flags;
@@ -2311,7 +2062,7 @@ static void iwl_config_ap(struct iwl_priv *priv)
/* RXON - unassoc (to set timing command) */
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
/* RXON Timing */
iwl_setup_rxon_timing(priv);
@@ -2321,7 +2072,8 @@ static void iwl_config_ap(struct iwl_priv *priv)
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
"Attempting to continue.\n");
- iwl_set_rxon_chain(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
/* FIXME: what should be the assoc_id for AP? */
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -2347,7 +2099,7 @@ static void iwl_config_ap(struct iwl_priv *priv)
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_activate_qos(priv, 1);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -2360,194 +2112,6 @@ static void iwl_config_ap(struct iwl_priv *priv)
* clear sta table, add BCAST sta... */
}
-
-static int iwl_mac_config_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_if_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
- int rc;
-
- if (conf == NULL)
- return -EIO;
-
- if (priv->vif != vif) {
- IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n");
- return 0;
- }
-
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
- conf->changed & IEEE80211_IFCC_BEACON) {
- struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
- if (!beacon)
- return -ENOMEM;
- mutex_lock(&priv->mutex);
- rc = iwl_mac_beacon_update(hw, beacon);
- mutex_unlock(&priv->mutex);
- if (rc)
- return rc;
- }
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- mutex_lock(&priv->mutex);
-
- if (conf->bssid)
- IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid);
-
-/*
- * very dubious code was here; the probe filtering flag is never set:
- *
- if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
- !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
- */
-
- if (priv->iw_mode == NL80211_IFTYPE_AP) {
- if (!conf->bssid) {
- conf->bssid = priv->mac_addr;
- memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
- IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n",
- conf->bssid);
- }
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
- }
-
- if (iwl_is_rfkill(priv))
- goto done;
-
- if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
- !is_multicast_ether_addr(conf->bssid)) {
- /* If there is currently a HW scan going on in the background
- * then we need to cancel it else the RXON below will fail. */
- if (iwl_scan_cancel_timeout(priv, 100)) {
- IWL_WARN(priv, "Aborted scan still in progress "
- "after 100ms\n");
- IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
- mutex_unlock(&priv->mutex);
- return -EAGAIN;
- }
- memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
-
- /* TODO: Audit driver for usage of these members and see
- * if mac80211 deprecates them (priv->bssid looks like it
- * shouldn't be there, but I haven't scanned the IBSS code
- * to verify) - jpk */
- memcpy(priv->bssid, conf->bssid, ETH_ALEN);
-
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl_config_ap(priv);
- else {
- rc = iwl_commit_rxon(priv);
- if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
- iwl_rxon_add_station(
- priv, priv->active_rxon.bssid_addr, 1);
- }
-
- } else {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
- }
-
- done:
- IWL_DEBUG_MAC80211(priv, "leave\n");
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- mutex_lock(&priv->mutex);
-
- if (iwl_is_ready_rf(priv)) {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
- }
- if (priv->vif == conf->vif) {
- priv->vif = NULL;
- memset(priv->bssid, 0, ETH_ALEN);
- }
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
-
-#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
-static void iwl_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes)
-{
- struct iwl_priv *priv = hw->priv;
-
- IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
-
- if (changes & BSS_CHANGED_ERP_PREAMBLE) {
- IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
- bss_conf->use_short_preamble);
- if (bss_conf->use_short_preamble)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
- else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
- }
-
- if (changes & BSS_CHANGED_ERP_CTS_PROT) {
- IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
- if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
- priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
- else
- priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
- }
-
- if (changes & BSS_CHANGED_HT) {
- iwl_ht_conf(priv, bss_conf);
- iwl_set_rxon_chain(priv);
- }
-
- if (changes & BSS_CHANGED_ASSOC) {
- IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
- /* This should never happen as this function should
- * never be called from interrupt context. */
- if (WARN_ON_ONCE(in_interrupt()))
- return;
- if (bss_conf->assoc) {
- priv->assoc_id = bss_conf->aid;
- priv->beacon_int = bss_conf->beacon_int;
- priv->power_data.dtim_period = bss_conf->dtim_period;
- priv->timestamp = bss_conf->timestamp;
- priv->assoc_capability = bss_conf->assoc_capability;
-
- /* we have just associated, don't start scan too early
- * leave time for EAPOL exchange to complete
- */
- priv->next_scan_jiffies = jiffies +
- IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
- mutex_lock(&priv->mutex);
- iwl_post_associate(priv);
- mutex_unlock(&priv->mutex);
- } else {
- priv->assoc_id = 0;
- IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc);
- }
- } else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
- IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes);
- iwl_send_rxon_assoc(priv);
- }
-
-}
-
static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *keyconf, const u8 *addr,
u32 iv32, u16 *phase1key)
@@ -2579,7 +2143,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
addr = sta ? sta->addr : iwl_bcast_addr;
- sta_id = iwl_find_station(priv, addr);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@@ -2630,49 +2194,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- int q;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- if (queue >= AC_NUM) {
- IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
- return 0;
- }
-
- q = AC_NUM - 1 - queue;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
- priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
- priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
- priv->qos_data.def_qos_parm.ac[q].edca_txop =
- cpu_to_le16((params->txop * 32));
-
- priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
- priv->qos_data.qos_active = 1;
-
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl_activate_qos(priv, 1);
- else if (priv->assoc_id && iwl_is_associated(priv))
- iwl_activate_qos(priv, 0);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
-}
-
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
@@ -2715,41 +2236,6 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
return 0;
}
-static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct iwl_priv *priv = hw->priv;
- int i, avail;
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- unsigned long flags;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- for (i = 0; i < AC_NUM; i++) {
- txq = &priv->txq[i];
- q = &txq->q;
- avail = iwl_queue_space(q);
-
- stats[i].len = q->n_window - avail;
- stats[i].limit = q->n_window - q->high_mark;
- stats[i].count = q->n_window;
-
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
- return 0;
-}
-
static int iwl_mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
@@ -2762,120 +2248,6 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
-
- mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- spin_lock_irqsave(&priv->lock, flags);
- memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
- spin_unlock_irqrestore(&priv->lock, flags);
-
- iwl_reset_qos(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->assoc_id = 0;
- priv->assoc_capability = 0;
- priv->assoc_station_added = 0;
-
- /* new association get rid of ibss beacon skb */
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = NULL;
-
- priv->beacon_int = priv->hw->conf.beacon_int;
- priv->timestamp = 0;
- if ((priv->iw_mode == NL80211_IFTYPE_STATION))
- priv->beacon_int = 0;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
- /* we are restarting association process
- * clear RXON_FILTER_ASSOC_MSK bit
- */
- if (priv->iw_mode != NL80211_IFTYPE_AP) {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_commit_rxon(priv);
- }
-
- iwl_power_update_mode(priv, 0);
-
- /* Per mac80211.h: This is only used in IBSS mode... */
- if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-
- /* switch to CAM during association period.
- * the ucode will block any association/authentication
- * frome during assiciation period if it can not hear
- * the AP because of PM. the timer enable PM back is
- * association do not complete
- */
- if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
- IEEE80211_CHAN_RADAR))
- iwl_power_disable_management(priv, 3000);
-
- IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
- iwl_set_rate(priv);
-
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- __le64 timestamp;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
- IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = skb;
-
- priv->assoc_id = 0;
- timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- spin_unlock_irqrestore(&priv->lock, flags);
-
- iwl_reset_qos(priv);
-
- iwl_post_associate(priv);
-
-
- return 0;
-}
-
/*****************************************************************************
*
* sysfs attributes
@@ -3025,7 +2397,7 @@ static ssize_t store_flags(struct device *d,
else {
IWL_DEBUG_INFO(priv, "Commit rxon.flags = 0x%04X\n", flags);
priv->staging_rxon.flags = cpu_to_le32(flags);
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -3066,7 +2438,7 @@ static ssize_t store_filter_flags(struct device *d,
"0x%04X\n", filter_flags);
priv->staging_rxon.filter_flags =
cpu_to_le32(filter_flags);
- iwl_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -3397,18 +2769,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_free_eeprom;
/* At this point both hw and priv are initialized. */
- /**********************************
- * 7. Initialize module parameters
- **********************************/
-
- /* Disable radio (SW RF KILL) via parameter when loading driver */
- if (priv->cfg->mod_params->disable) {
- set_bit(STATUS_RF_KILL_SW, &priv->status);
- IWL_DEBUG_INFO(priv, "Radio disabled.\n");
- }
-
/********************
- * 8. Setup services
+ * 7. Setup services
********************/
spin_lock_irqsave(&priv->lock, flags);
iwl_disable_interrupts(priv);
@@ -3432,7 +2794,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_setup_rx_handlers(priv);
/**********************************
- * 9. Setup and register mac80211
+ * 8. Setup and register mac80211
**********************************/
/* enable interrupts if needed: hw bug w/a */
@@ -3450,7 +2812,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = iwl_dbgfs_register(priv, DRV_NAME);
if (err)
- IWL_ERR(priv, "failed to create debugfs files\n");
+ IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -3533,7 +2895,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_rx_queue_free(priv, &priv->rxq);
iwl_hw_txq_ctx_free(priv);
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_eeprom_free(priv);
@@ -3561,45 +2923,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
ieee80211_free_hw(priv->hw);
}
-#ifdef CONFIG_PM
-
-static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
-
- if (priv->is_open) {
- set_bit(STATUS_IN_SUSPEND, &priv->status);
- iwl_mac_stop(priv->hw);
- priv->is_open = 1;
- }
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-static int iwl_pci_resume(struct pci_dev *pdev)
-{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
- int ret;
-
- pci_set_power_state(pdev, PCI_D0);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
- pci_restore_state(pdev);
- iwl_enable_interrupts(priv);
-
- if (priv->is_open)
- iwl_mac_start(priv->hw);
-
- clear_bit(STATUS_IN_SUSPEND, &priv->status);
- return 0;
-}
-
-#endif /* CONFIG_PM */
/*****************************************************************************
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 29d40746da6..7b84d5246b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2469,11 +2469,12 @@ struct iwl_ssid_ie {
u8 ssid[32];
} __attribute__ ((packed));
-#define PROBE_OPTION_MAX_API1 0x4
-#define PROBE_OPTION_MAX 0x14
+#define PROBE_OPTION_MAX_3945 4
+#define PROBE_OPTION_MAX 20
#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
#define IWL_GOOD_CRC_TH cpu_to_le16(1)
#define IWL_MAX_SCAN_SIZE 1024
+#define IWL_MAX_PROBE_REQUEST 200
/*
* REPLY_SCAN_CMD = 0x80 (command)
@@ -2552,7 +2553,7 @@ struct iwl3945_scan_cmd {
struct iwl3945_tx_cmd tx_cmd;
/* For directed active scans (set to all-0s otherwise) */
- struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_API1];
+ struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945];
/*
* Probe request frame, followed by channel list.
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c54fb93e9d7..3dec2d25fa3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -735,6 +735,8 @@ int iwl_full_rxon_required(struct iwl_priv *priv)
priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
(priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+ (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates !=
+ priv->active_rxon.ofdm_ht_triple_stream_basic_rates) ||
(priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
return 1;
@@ -821,7 +823,8 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
- iwl_set_rxon_chain(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X "
"rxon flags 0x%X operation mode :0x%X "
@@ -901,10 +904,11 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
* never called for monitor mode. The only way mac80211 informs us about
* monitor mode is through configuring filters (call to configure_filter).
*/
-static bool iwl_is_monitor_mode(struct iwl_priv *priv)
+bool iwl_is_monitor_mode(struct iwl_priv *priv)
{
return !!(priv->staging_rxon.filter_flags & RXON_FILTER_PROMISC_MSK);
}
+EXPORT_SYMBOL(iwl_is_monitor_mode);
/**
* iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
@@ -1068,11 +1072,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
RXON_FILTER_ACCEPT_GRP_MSK;
break;
- case NL80211_IFTYPE_MONITOR:
- priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
- priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
- RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
- break;
default:
IWL_ERR(priv, "Unsupported interface type %d\n", mode);
break;
@@ -1117,6 +1116,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+ priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
}
EXPORT_SYMBOL(iwl_connection_init_rx_config);
@@ -1305,7 +1305,10 @@ int iwl_setup_mac(struct iwl_priv *priv)
BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->custom_regulatory = true;
- hw->wiphy->max_scan_ssids = 1;
+
+ hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+ /* we create the 802.11 header and a zero-length SSID element */
+ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
@@ -1366,7 +1369,7 @@ int iwl_init_drv(struct iwl_priv *priv)
mutex_init(&priv->mutex);
/* Clear the driver's (not device's) station table */
- iwl_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
@@ -1378,7 +1381,9 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
/* Choose which receivers/antennas to use */
- iwl_set_rxon_chain(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
iwl_init_scan_params(priv);
iwl_reset_qos(priv);
@@ -2054,7 +2059,7 @@ void iwl_bg_rf_kill(struct work_struct *work)
"HW and/or SW RF Kill no longer active, restarting "
"device\n");
if (!test_bit(STATUS_EXIT_PENDING, &priv->status) &&
- test_bit(STATUS_ALIVE, &priv->status))
+ priv->is_open)
queue_work(priv->workqueue, &priv->restart);
} else {
/* make sure mac80211 stop sending Tx frame */
@@ -2112,3 +2117,727 @@ void iwl_rx_reply_error(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_reply_error);
+void iwl_clear_isr_stats(struct iwl_priv *priv)
+{
+ memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
+}
+EXPORT_SYMBOL(iwl_clear_isr_stats);
+
+int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ int q;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (queue >= AC_NUM) {
+ IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+ return 0;
+ }
+
+ q = AC_NUM - 1 - queue;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+ priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+ priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ priv->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->txop * 32));
+
+ priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ priv->qos_data.qos_active = 1;
+
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
+ iwl_activate_qos(priv, 1);
+ else if (priv->assoc_id && iwl_is_associated(priv))
+ iwl_activate_qos(priv, 0);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ return 0;
+}
+EXPORT_SYMBOL(iwl_mac_conf_tx);
+
+static void iwl_ht_conf(struct iwl_priv *priv,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct ieee80211_sta_ht_cap *ht_conf;
+ struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+ struct ieee80211_sta *sta;
+
+ IWL_DEBUG_MAC80211(priv, "enter: \n");
+
+ if (!iwl_conf->is_ht)
+ return;
+
+
+ /*
+ * It is totally wrong to base global information on something
+ * that is valid only when associated, alas, this driver works
+ * that way and I don't know how to fix it.
+ */
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->hw, priv->bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ ht_conf = &sta->ht_cap;
+
+ if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+ iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
+ if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+ iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
+
+ iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+ iwl_conf->max_amsdu_size =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+
+ iwl_conf->supported_chan_width =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+ /*
+ * XXX: The HT configuration needs to be moved into iwl_mac_config()
+ * to be done there correctly.
+ */
+
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ if (conf_is_ht40_minus(&priv->hw->conf))
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ else if (conf_is_ht40_plus(&priv->hw->conf))
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+
+ /* If no above or below channel supplied disable FAT channel */
+ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
+ iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
+ iwl_conf->supported_chan_width = 0;
+
+ iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
+
+ memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
+
+ iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
+ iwl_conf->ht_protection =
+ bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ iwl_conf->non_GF_STA_present =
+ !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+ rcu_read_unlock();
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+void iwl_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct iwl_priv *priv = hw->priv;
+ int ret;
+
+ IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
+
+ if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+ IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
+ if (bss_conf->use_short_preamble)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ }
+
+ if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+ IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
+ if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+ priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+ }
+
+ if (changes & BSS_CHANGED_HT) {
+ iwl_ht_conf(priv, bss_conf);
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ }
+
+ if (changes & BSS_CHANGED_ASSOC) {
+ IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
+ /* This should never happen as this function should
+ * never be called from interrupt context. */
+ if (WARN_ON_ONCE(in_interrupt()))
+ return;
+ if (bss_conf->assoc) {
+ priv->assoc_id = bss_conf->aid;
+ priv->beacon_int = bss_conf->beacon_int;
+ priv->power_data.dtim_period = bss_conf->dtim_period;
+ priv->timestamp = bss_conf->timestamp;
+ priv->assoc_capability = bss_conf->assoc_capability;
+
+ /* we have just associated, don't start scan too early
+ * leave time for EAPOL exchange to complete
+ */
+ priv->next_scan_jiffies = jiffies +
+ IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+ mutex_lock(&priv->mutex);
+ priv->cfg->ops->lib->post_associate(priv);
+ mutex_unlock(&priv->mutex);
+ } else {
+ priv->assoc_id = 0;
+ IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc);
+ }
+ } else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+ IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes);
+ ret = iwl_send_rxon_assoc(priv);
+ if (!ret)
+ /* Sync active_rxon with latest change. */
+ memcpy((void *)&priv->active_rxon,
+ &priv->staging_rxon,
+ sizeof(struct iwl_rxon_cmd));
+ }
+
+}
+EXPORT_SYMBOL(iwl_bss_info_changed);
+
+int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ __le64 timestamp;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+ IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ priv->assoc_id = 0;
+ timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+ priv->timestamp = le64_to_cpu(timestamp);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_reset_qos(priv);
+
+ priv->cfg->ops->lib->post_associate(priv);
+
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_mac_beacon_update);
+
+int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+ if (mode == NL80211_IFTYPE_ADHOC) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv,
+ priv->band,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info || !is_channel_ibss(ch_info)) {
+ IWL_ERR(priv, "channel %d not IBSS channel\n",
+ le16_to_cpu(priv->staging_rxon.channel));
+ return -EINVAL;
+ }
+ }
+
+ iwl_connection_init_rx_config(priv, mode);
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+ priv->cfg->ops->smgmt->clear_station_table(priv);
+
+ /* dont commit rxon if rf-kill is on*/
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
+ return -EAGAIN;
+ }
+
+ iwlcore_commit_rxon(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_set_mode);
+
+int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
+
+ if (priv->vif) {
+ IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
+ return -EOPNOTSUPP;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->vif = conf->vif;
+ priv->iw_mode = conf->type;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+
+ if (conf->mac_addr) {
+ IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ }
+
+ if (iwl_set_mode(priv, conf->type) == -EAGAIN)
+ /* we are not ready, will run again when ready */
+ set_bit(STATUS_MODE_PENDING, &priv->status);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ return 0;
+}
+EXPORT_SYMBOL(iwl_mac_add_interface);
+
+void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ mutex_lock(&priv->mutex);
+
+ if (iwl_is_ready_rf(priv)) {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv);
+ }
+ if (priv->vif == conf->vif) {
+ priv->vif = NULL;
+ memset(priv->bssid, 0, ETH_ALEN);
+ }
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+EXPORT_SYMBOL(iwl_mac_remove_interface);
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
+ unsigned long flags = 0;
+ int ret = 0;
+ u16 ch;
+ int scan_active = 0;
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
+ conf->channel->hw_value, changed);
+
+ if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ scan_active = 1;
+ IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+ }
+
+
+ /* during scanning mac80211 will delay channel setting until
+ * scan finish with changed = 0
+ */
+ if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ if (scan_active)
+ goto set_ch_out;
+
+ ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
+ ret = -EINVAL;
+ goto set_ch_out;
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+ !is_channel_ibss(ch_info)) {
+ IWL_ERR(priv, "channel %d in band %d not "
+ "IBSS channel\n",
+ conf->channel->hw_value, conf->channel->band);
+ ret = -EINVAL;
+ goto set_ch_out;
+ }
+
+ priv->current_ht_config.is_ht = conf_is_ht(conf);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
+ priv->staging_rxon.flags = 0;
+
+ iwl_set_rxon_channel(priv, conf->channel);
+
+ iwl_set_flags_for_band(priv, conf->channel->band);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_ch_out:
+ /* The list of supported rates and rate mask can be different
+ * for each band; since the band may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ if (conf->flags & IEEE80211_CONF_PS)
+ ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3);
+ else
+ ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM);
+ if (ret)
+ IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
+
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+ priv->tx_power_user_lmt, conf->power_level);
+
+ iwl_set_tx_power(priv, conf->power_level, false);
+ }
+
+ /* call to ensure that 4965 rx_chain is set properly in monitor mode */
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
+ if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
+ if (conf->radio_enabled &&
+ iwl_radio_kill_sw_enable_radio(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - "
+ "waiting for uCode\n");
+ goto out;
+ }
+
+ if (!conf->radio_enabled)
+ iwl_radio_kill_sw_disable_radio(priv);
+ }
+
+ if (!conf->radio_enabled) {
+ IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
+ goto out;
+ }
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ goto out;
+ }
+
+ if (scan_active)
+ goto out;
+
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwlcore_commit_rxon(priv);
+ else
+ IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n");
+
+
+out:
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_mac_config);
+
+int iwl_mac_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ int rc;
+
+ if (conf == NULL)
+ return -EIO;
+
+ if (priv->vif != vif) {
+ IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n");
+ return 0;
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+ conf->changed & IEEE80211_IFCC_BEACON) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ mutex_lock(&priv->mutex);
+ rc = iwl_mac_beacon_update(hw, beacon);
+ mutex_unlock(&priv->mutex);
+ if (rc)
+ return rc;
+ }
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ mutex_lock(&priv->mutex);
+
+ if (conf->bssid)
+ IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid);
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+ !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
+ if (!conf->bssid) {
+ conf->bssid = priv->mac_addr;
+ memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+ IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n",
+ conf->bssid);
+ }
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
+ }
+
+ if (iwl_is_rfkill(priv))
+ goto done;
+
+ if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+ !is_multicast_ether_addr(conf->bssid)) {
+ /* If there is currently a HW scan going on in the background
+ * then we need to cancel it else the RXON below will fail. */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARN(priv, "Aborted scan still in progress "
+ "after 100ms\n");
+ IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return -EAGAIN;
+ }
+ memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+ /* TODO: Audit driver for usage of these members and see
+ * if mac80211 deprecates them (priv->bssid looks like it
+ * shouldn't be there, but I haven't scanned the IBSS code
+ * to verify) - jpk */
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
+ iwlcore_config_ap(priv);
+ else {
+ rc = iwlcore_commit_rxon(priv);
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
+ iwl_rxon_add_station(
+ priv, priv->active_rxon.bssid_addr, 1);
+ }
+
+ } else {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv);
+ }
+
+ done:
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_mac_config_interface);
+
+int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct iwl_priv *priv = hw->priv;
+ int i, avail;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < AC_NUM; i++) {
+ txq = &priv->txq[i];
+ q = &txq->q;
+ avail = iwl_queue_space(q);
+
+ stats[i].len = q->n_window - avail;
+ stats[i].limit = q->n_window - q->high_mark;
+ stats[i].count = q->n_window;
+
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_mac_get_tx_stats);
+
+void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_reset_qos(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = 0;
+ priv->assoc_capability = 0;
+ priv->assoc_station_added = 0;
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = NULL;
+
+ priv->beacon_int = priv->hw->conf.beacon_int;
+ priv->timestamp = 0;
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION))
+ priv->beacon_int = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ /* we are restarting association process
+ * clear RXON_FILTER_ASSOC_MSK bit
+ */
+ if (priv->iw_mode != NL80211_IFTYPE_AP) {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv);
+ }
+
+ iwl_power_update_mode(priv, 0);
+
+ /* Per mac80211.h: This is only used in IBSS mode... */
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+
+ /* switch to CAM during association period.
+ * the ucode will block any association/authentication
+ * frome during assiciation period if it can not hear
+ * the AP because of PM. the timer enable PM back is
+ * association do not complete
+ */
+ if (priv->hw->conf.channel->flags &
+ (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR))
+ iwl_power_disable_management(priv, 3000);
+
+ IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+EXPORT_SYMBOL(iwl_mac_reset_tsf);
+
+#ifdef CONFIG_PM
+
+int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ /*
+ * This function is called when system goes into suspend state
+ * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
+ * first but since iwl_mac_stop() has no knowledge of who the caller is,
+ * it will not call apm_ops.stop() to stop the DMA operation.
+ * Calling apm_ops.stop here to make sure we stop the DMA.
+ */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_pci_suspend);
+
+int iwl_pci_resume(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ pci_restore_state(pdev);
+ iwl_enable_interrupts(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_pci_resume);
+
+#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index a8eac8c3c1f..d4c60afa289 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -83,9 +83,21 @@ struct iwl_cmd;
#define IWL_SKU_A 0x2
#define IWL_SKU_N 0x8
+struct iwl_station_mgmt_ops {
+ u8 (*add_station)(struct iwl_priv *priv, const u8 *addr,
+ int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
+ int (*remove_station)(struct iwl_priv *priv, const u8 *addr,
+ int is_ap);
+ u8 (*find_station)(struct iwl_priv *priv, const u8 *addr);
+ void (*clear_station_table)(struct iwl_priv *priv);
+};
+
struct iwl_hcmd_ops {
int (*rxon_assoc)(struct iwl_priv *priv);
+ int (*commit_rxon)(struct iwl_priv *priv);
+ void (*set_rxon_chain)(struct iwl_priv *priv);
};
+
struct iwl_hcmd_utils_ops {
u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
@@ -149,6 +161,9 @@ struct iwl_lib_ops {
int (*send_tx_power) (struct iwl_priv *priv);
void (*update_chain_flags)(struct iwl_priv *priv);
void (*temperature) (struct iwl_priv *priv);
+ void (*post_associate) (struct iwl_priv *priv);
+ void (*config_ap) (struct iwl_priv *priv);
+
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
};
@@ -157,10 +172,10 @@ struct iwl_ops {
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
+ const struct iwl_station_mgmt_ops *smgmt;
};
struct iwl_mod_params {
- int disable; /* def: 0 = enable radio */
int sw_crypto; /* def: 0 = using hardware encryption */
u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
@@ -225,6 +240,8 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
void iwl_hw_detect(struct iwl_priv *priv);
void iwl_reset_qos(struct iwl_priv *priv);
void iwl_activate_qos(struct iwl_priv *priv, u8 force);
+int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
int iwl_check_rxon_cmd(struct iwl_priv *priv);
int iwl_full_rxon_required(struct iwl_priv *priv);
@@ -249,6 +266,27 @@ int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv);
+bool iwl_is_monitor_mode(struct iwl_priv *priv);
+void iwl_post_associate(struct iwl_priv *priv);
+void iwl_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes);
+int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+int iwl_commit_rxon(struct iwl_priv *priv);
+int iwl_set_mode(struct iwl_priv *priv, int mode);
+int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
+void iwl_config_ap(struct iwl_priv *priv);
+int iwl_mac_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf);
+int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats);
+void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
/*****************************************************
* RX handlers.
@@ -358,8 +396,8 @@ int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
int iwl_scan_initiate(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
-u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band,
- struct ieee80211_mgmt *frame, int left);
+u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
+ const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
enum ieee80211_band band,
@@ -432,12 +470,17 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
return pci_lnk_ctl;
}
+#ifdef CONFIG_PM
+int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+int iwl_pci_resume(struct pci_dev *pdev);
+#endif /* CONFIG_PM */
/*****************************************************
* Error Handling Debugging
******************************************************/
void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
+void iwl_clear_isr_stats(struct iwl_priv *priv);
/*****************************************************
* GEOS
@@ -458,7 +501,6 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_TEMPERATURE 8
#define STATUS_GEO_CONFIGURED 9
#define STATUS_EXIT_PENDING 10
-#define STATUS_IN_SUSPEND 11
#define STATUS_STATISTICS 12
#define STATUS_SCANNING 13
#define STATUS_SCAN_ABORTING 14
@@ -528,7 +570,14 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
{
return priv->cfg->ops->hcmd->rxon_assoc(priv);
}
-
+static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
+{
+ return priv->cfg->ops->hcmd->commit_rxon(priv);
+}
+static inline void iwlcore_config_ap(struct iwl_priv *priv)
+{
+ priv->cfg->ops->lib->config_ap(priv);
+}
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
struct iwl_priv *priv, enum ieee80211_band band)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 65d1a7f2db9..db069801bc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -75,6 +75,7 @@ struct iwl_debugfs {
struct dentry *file_log_event;
struct dentry *file_channels;
struct dentry *file_status;
+ struct dentry *file_interrupt;
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 64eb585f157..ffc4be3842b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -389,7 +389,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
- (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+ ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
@@ -456,8 +456,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
test_bit(STATUS_GEO_CONFIGURED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
test_bit(STATUS_EXIT_PENDING, &priv->status));
- pos += scnprintf(buf + pos, bufsz - pos, "STATUS_IN_SUSPEND:\t %d\n",
- test_bit(STATUS_IN_SUSPEND, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
test_bit(STATUS_STATISTICS, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
@@ -475,6 +473,95 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ int cnt = 0;
+ char *buf;
+ int bufsz = 24 * 64; /* 24 items * 64 char per item */
+ ssize_t ret;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Interrupt Statistics Report:\n");
+
+ pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
+ priv->isr_stats.hw);
+ pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
+ priv->isr_stats.sw);
+ if (priv->isr_stats.sw > 0) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tLast Restarting Code: 0x%X\n",
+ priv->isr_stats.sw_err);
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
+ priv->isr_stats.sch);
+ pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
+ priv->isr_stats.alive);
+#endif
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "HW RF KILL switch toggled:\t %u\n",
+ priv->isr_stats.rfkill);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
+ priv->isr_stats.ctkill);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
+ priv->isr_stats.wakeup);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Rx command responses:\t\t %u\n",
+ priv->isr_stats.rx);
+ for (cnt = 0; cnt < REPLY_MAX; cnt++) {
+ if (priv->isr_stats.rx_handlers[cnt] > 0)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tRx handler[%36s]:\t\t %u\n",
+ get_cmd_string(cnt),
+ priv->isr_stats.rx_handlers[cnt]);
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
+ priv->isr_stats.tx);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
+ priv->isr_stats.unhandled);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ u32 reset_flag;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%x", &reset_flag) != 1)
+ return -EFAULT;
+ if (reset_flag == 0)
+ iwl_clear_isr_stats(priv);
+
+ return count;
+}
+
+
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(eeprom);
@@ -483,6 +570,7 @@ DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
+DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
/*
* Create the debugfs files and directories
@@ -518,6 +606,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(tx_statistics, data);
DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_FILE(status, data);
+ DEBUGFS_ADD_FILE(interrupt, data);
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
@@ -548,6 +637,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index cf7f0db58fc..5aa76a70632 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -70,6 +70,7 @@ extern struct iwl_ops iwl5000_ops;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
+extern struct iwl_station_mgmt_ops iwl5000_station_mgmt;
/* shared functions from iwl-5000.c */
extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
@@ -822,6 +823,21 @@ enum {
MEASUREMENT_ACTIVE = (1 << 1),
};
+/* interrupt statistics */
+struct isr_statistics {
+ u32 hw;
+ u32 sw;
+ u32 sw_err;
+ u32 sch;
+ u32 alive;
+ u32 rfkill;
+ u32 ctkill;
+ u32 wakeup;
+ u32 rx;
+ u32 rx_handlers[REPLY_MAX];
+ u32 tx;
+ u32 unhandled;
+};
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
@@ -877,9 +893,7 @@ struct iwl_priv {
unsigned long scan_start_tsf;
void *scan;
int scan_bands;
- int one_direct_scan;
- u8 direct_ssid_len;
- u8 direct_ssid[IW_ESSID_MAX_SIZE];
+ struct cfg80211_scan_request *scan_request;
u8 scan_tx_ant[IEEE80211_NUM_BANDS];
u8 mgmt_tx_ant;
@@ -978,6 +992,9 @@ struct iwl_priv {
u64 bytes;
} tx_stats[3], rx_stats[3];
+ /* counts interrupts */
+ struct isr_statistics isr_stats;
+
struct iwl_power_mgr power_data;
struct iwl_notif_statistics statistics;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index 2ad9faf1508..65605ad44e4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -91,7 +91,6 @@ int iwl_rfkill_init(struct iwl_priv *priv)
priv->rfkill->data = priv;
priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
- priv->rfkill->user_claim_unsupported = 1;
priv->rfkill->dev.class->suspend = NULL;
priv->rfkill->dev.class->resume = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 8f65908f66f..fae84262efb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1102,13 +1102,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
rx_status.flag |= RX_FLAG_SHORTPRE;
- /* Take shortcut when only in monitor mode */
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- iwl_pass_packet_to_mac80211(priv, include_phy,
- rxb, &rx_status);
- return;
- }
-
network_packet = iwl_is_network_packet(priv, header);
if (network_packet) {
priv->last_rx_rssi = rx_status.signal;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 23644cf884f..799f5eb61ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -448,13 +448,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
unsigned long flags;
struct iwl_priv *priv = hw->priv;
int ret;
- u8 *ssid = NULL;
- size_t ssid_len = 0;
-
- if (req->n_ssids) {
- ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
- }
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -488,13 +481,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
- if (ssid_len) {
- priv->one_direct_scan = 1;
- priv->direct_ssid_len = ssid_len;
- memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
- } else {
- priv->one_direct_scan = 0;
- }
+ priv->scan_request = req;
ret = iwl_scan_initiate(priv);
@@ -533,73 +520,14 @@ void iwl_bg_scan_check(struct work_struct *data)
EXPORT_SYMBOL(iwl_bg_scan_check);
/**
- * iwl_supported_rate_to_ie - fill in the supported rate in IE field
- *
- * return : set the bit for each supported rate insert in ie
- */
-static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
- u16 basic_rate, int *left)
-{
- u16 ret_rates = 0, bit;
- int i;
- u8 *cnt = ie;
- u8 *rates = ie + 1;
-
- for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
- if (bit & supported_rate) {
- ret_rates |= bit;
- rates[*cnt] = iwl_rates[i].ieee |
- ((bit & basic_rate) ? 0x80 : 0x00);
- (*cnt)++;
- (*left)--;
- if ((*left <= 0) ||
- (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
- break;
- }
- }
-
- return ret_rates;
-}
-
-
-static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
- u8 *pos, int *left)
-{
- struct ieee80211_ht_cap *ht_cap;
-
- if (!sband || !sband->ht_cap.ht_supported)
- return;
-
- if (*left < sizeof(struct ieee80211_ht_cap))
- return;
-
- *pos++ = sizeof(struct ieee80211_ht_cap);
- ht_cap = (struct ieee80211_ht_cap *) pos;
-
- ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
- memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16);
- ht_cap->ampdu_params_info =
- (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) |
- ((sband->ht_cap.ampdu_density << 2) &
- IEEE80211_HT_AMPDU_PARM_DENSITY);
- *left -= sizeof(struct ieee80211_ht_cap);
-}
-
-/**
* iwl_fill_probe_req - fill in all required fields and IE for probe request
*/
-u16 iwl_fill_probe_req(struct iwl_priv *priv,
- enum ieee80211_band band,
- struct ieee80211_mgmt *frame,
- int left)
+u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
+ const u8 *ies, int ie_len, int left)
{
int len = 0;
u8 *pos = NULL;
- u16 active_rates, ret_rates, cck_rates, active_rate_basic;
- const struct ieee80211_supported_band *sband =
- iwl_get_hw_mode(priv, band);
-
/* Make sure there is enough space for the probe request,
* two mandatory IEs and the data */
@@ -627,62 +555,12 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv,
len += 2;
- /* fill in supported rate */
- left -= 2;
- if (left < 0)
- return 0;
-
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos = 0;
-
- /* exclude 60M rate */
- active_rates = priv->rates_mask;
- active_rates &= ~IWL_RATE_60M_MASK;
-
- active_rate_basic = active_rates & IWL_BASIC_RATES_MASK;
-
- cck_rates = IWL_CCK_RATES_MASK & active_rates;
- ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
- active_rate_basic, &left);
- active_rates &= ~ret_rates;
-
- ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
- active_rate_basic, &left);
- active_rates &= ~ret_rates;
-
- len += 2 + *pos;
- pos += (*pos) + 1;
+ if (WARN_ON(left < ie_len))
+ return len;
- if (active_rates == 0)
- goto fill_end;
-
- /* fill in supported extended rate */
- /* ...next IE... */
- left -= 2;
- if (left < 0)
- return 0;
- /* ... fill it in... */
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos = 0;
- iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left);
- if (*pos > 0) {
- len += 2 + *pos;
- pos += (*pos) + 1;
- } else {
- pos--;
- }
-
- fill_end:
-
- left -= 2;
- if (left < 0)
- return 0;
-
- *pos++ = WLAN_EID_HT_CAPABILITY;
- *pos = 0;
- iwl_ht_cap_to_ie(sband, pos, &left);
- if (*pos > 0)
- len += 2 + *pos;
+ memcpy(pos, ies, ie_len);
+ len += ie_len;
+ left -= ie_len;
return (u16)len;
}
@@ -703,10 +581,10 @@ static void iwl_bg_request_scan(struct work_struct *data)
u32 rate_flags = 0;
u16 cmd_len;
enum ieee80211_band band;
- u8 n_probes = 2;
+ u8 n_probes = 0;
u8 rx_chain = priv->hw_params.valid_rx_ant;
u8 rate;
- DECLARE_SSID_BUF(ssid);
+ bool is_active = false;
conf = ieee80211_get_hw_conf(priv->hw);
@@ -796,19 +674,25 @@ static void iwl_bg_request_scan(struct work_struct *data)
scan_suspend_time, interval);
}
- /* We should add the ability for user to lock to PASSIVE ONLY */
- if (priv->one_direct_scan) {
- IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n",
- print_ssid(ssid, priv->direct_ssid,
- priv->direct_ssid_len));
- scan->direct_scan[0].id = WLAN_EID_SSID;
- scan->direct_scan[0].len = priv->direct_ssid_len;
- memcpy(scan->direct_scan[0].ssid,
- priv->direct_ssid, priv->direct_ssid_len);
- n_probes++;
- } else {
- IWL_DEBUG_SCAN(priv, "Start indirect scan.\n");
- }
+ if (priv->scan_request->n_ssids) {
+ int i, p = 0;
+ IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ /* always does wildcard anyway */
+ if (!priv->scan_request->ssids[i].ssid_len)
+ continue;
+ scan->direct_scan[p].id = WLAN_EID_SSID;
+ scan->direct_scan[p].len =
+ priv->scan_request->ssids[i].ssid_len;
+ memcpy(scan->direct_scan[p].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ n_probes++;
+ p++;
+ }
+ is_active = true;
+ } else
+ IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
@@ -828,7 +712,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
band = IEEE80211_BAND_5GHZ;
rate = IWL_RATE_6M_PLCP;
- scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ /*
+ * If active scaning is requested but a certain channel
+ * is marked passive, we can do active scanning if we
+ * detect transmissions.
+ */
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
/* Force use of chains B and C (0x6) for scan Rx for 4965
* Avoid A (0x1) because of its off-channel reception on A-band.
@@ -850,22 +739,22 @@ static void iwl_bg_request_scan(struct work_struct *data)
cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
(rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) |
(0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
-
- cmd_len = iwl_fill_probe_req(priv, band,
- (struct ieee80211_mgmt *)scan->data,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ cmd_len = iwl_fill_probe_req(priv,
+ (struct ieee80211_mgmt *)scan->data,
+ priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan));
scan->tx_cmd.len = cpu_to_le16(cmd_len);
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
+ if (iwl_is_monitor_mode(priv))
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
RXON_FILTER_BCON_AWARE_MSK);
scan->channel_count =
- iwl_get_channels_for_scan(priv, band, 1, /* active */
- n_probes,
+ iwl_get_channels_for_scan(priv, band, is_active, n_probes,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
if (scan->channel_count == 0) {
@@ -928,6 +817,7 @@ void iwl_bg_scan_completed(struct work_struct *work)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
+ priv->scan_request = NULL;
ieee80211_scan_completed(priv->hw, false);
/* Since setting the TXPOWER may have been deferred while
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 5798fe49c77..17a4dd2be1f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
return IWL_AP_ID;
} else {
u8 *da = ieee80211_get_DA(hdr);
- return iwl_find_station(priv, da);
+ return priv->cfg->ops->smgmt->find_station(priv, da);
}
}
EXPORT_SYMBOL(iwl_get_ra_sta_id);
@@ -300,7 +300,7 @@ EXPORT_SYMBOL(iwl_add_station_flags);
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
{
unsigned long flags;
- u8 sta_id = iwl_find_station(priv, addr);
+ u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
BUG_ON(sta_id == IWL_INVALID_STATION);
@@ -758,7 +758,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
int i;
DECLARE_MAC_BUF(mac);
- sta_id = iwl_find_station(priv, addr);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@@ -1019,7 +1019,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
rcu_read_unlock();
}
- sta_id = iwl_add_station_flags(priv, addr, is_ap,
+ sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap,
0, cur_ht_config);
/* Set up default rate scaling table in device's station table */
@@ -1053,7 +1053,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
/* If we are an AP, then find the station, or use BCAST */
case NL80211_IFTYPE_AP:
- sta_id = iwl_find_station(priv, hdr->addr1);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
return priv->hw_params.bcast_sta_id;
@@ -1061,12 +1061,12 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
case NL80211_IFTYPE_ADHOC:
- sta_id = iwl_find_station(priv, hdr->addr1);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
/* Create new station table entry */
- sta_id = iwl_add_station_flags(priv, hdr->addr1,
+ sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1,
0, CMD_ASYNC, NULL);
if (sta_id != IWL_INVALID_STATION)
@@ -1078,11 +1078,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
- /* If we are in monitor mode, use BCAST. This is required for
- * packet injection. */
- case NL80211_IFTYPE_MONITOR:
- return priv->hw_params.bcast_sta_id;
-
default:
IWL_WARN(priv, "Unknown mode of operation: %d\n",
priv->iw_mode);
@@ -1115,7 +1110,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
unsigned long flags;
int sta_id;
- sta_id = iwl_find_station(priv, addr);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION)
return -ENXIO;
@@ -1137,7 +1132,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
unsigned long flags;
int sta_id;
- sta_id = iwl_find_station(priv, addr);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
return -ENXIO;
@@ -1172,7 +1167,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
{
/* FIXME: need locking over ps_status ??? */
- u8 sta_id = iwl_find_station(priv, addr);
+ u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id != IWL_INVALID_STATION) {
u8 sta_awake = priv->stations[sta_id].
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 71d5b8a1a73..a82cca0a30c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -728,7 +728,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* drop all data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (priv->iw_mode != NL80211_IFTYPE_MONITOR ||
+ (!iwl_is_monitor_mode(priv) ||
!(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
@@ -1183,8 +1183,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
__func__, ra, tid);
sta_id = iwl_find_station(priv, ra);
- if (sta_id == IWL_INVALID_STATION)
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_ERR(priv, "Start AGG on invalid station\n");
return -ENXIO;
+ }
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
@@ -1192,8 +1194,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
}
txq_id = iwl_txq_ctx_activate_free(priv);
- if (txq_id == -1)
+ if (txq_id == -1) {
+ IWL_ERR(priv, "No free aggregation queue available\n");
return -ENXIO;
+ }
spin_lock_irqsave(&priv->sta_lock, flags);
tid_data = &priv->stations[sta_id].tid[tid];
@@ -1207,7 +1211,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
return ret;
if (tid_data->tfds_in_queue == 0) {
- IWL_ERR(priv, "HW queue is empty\n");
+ IWL_DEBUG_HT(priv, "HW queue is empty\n");
tid_data->agg.state = IWL_AGG_ON;
ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
} else {
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 617c4235d97..84feeb70fea 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -149,7 +149,7 @@ out:
*
* NOTE: This does not clear or otherwise alter the device's station table.
*/
-static void iwl3945_clear_stations_table(struct iwl_priv *priv)
+void iwl3945_clear_stations_table(struct iwl_priv *priv)
{
unsigned long flags;
@@ -164,7 +164,7 @@ static void iwl3945_clear_stations_table(struct iwl_priv *priv)
/**
* iwl3945_add_station - Add station to station tables in driver and device
*/
-u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info)
{
int i;
int index = IWL_INVALID_STATION;
@@ -233,50 +233,6 @@ u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flag
}
-static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
-{
- int rc = 0;
- struct iwl_rx_packet *res = NULL;
- struct iwl3945_rxon_assoc_cmd rxon_assoc;
- struct iwl_host_cmd cmd = {
- .id = REPLY_RXON_ASSOC,
- .len = sizeof(rxon_assoc),
- .meta.flags = CMD_WANT_SKB,
- .data = &rxon_assoc,
- };
- const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
-
- if ((rxon1->flags == rxon2->flags) &&
- (rxon1->filter_flags == rxon2->filter_flags) &&
- (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
- (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
- IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
- return 0;
- }
-
- rxon_assoc.flags = priv->staging_rxon.flags;
- rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
- rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
- rxon_assoc.reserved = 0;
-
- rc = iwl_send_cmd_sync(priv, &cmd);
- if (rc)
- return rc;
-
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
- rc = -EIO;
- }
-
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
-
- return rc;
-}
-
/**
* iwl3945_get_antenna_flags - Get antenna flags for RXON command
* @priv: eeprom and antenna fields are used to determine antenna flags
@@ -314,150 +270,6 @@ __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
return 0; /* "diversity" is default if error */
}
-/**
- * iwl3945_commit_rxon - commit staging_rxon to hardware
- *
- * The RXON command in staging_rxon is committed to the hardware and
- * the active_rxon structure is updated with the new data. This
- * function correctly transitions out of the RXON_ASSOC_MSK state if
- * a HW tune is required based on the RXON structure changes.
- */
-static int iwl3945_commit_rxon(struct iwl_priv *priv)
-{
- /* cast away the const for active_rxon in this function */
- struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
- struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
- int rc = 0;
- bool new_assoc =
- !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
-
- if (!iwl_is_alive(priv))
- return -1;
-
- /* always get timestamp with Rx frame */
- staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK;
-
- /* select antenna */
- staging_rxon->flags &=
- ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
- staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
-
- rc = iwl_check_rxon_cmd(priv);
- if (rc) {
- IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
- return -EINVAL;
- }
-
- /* If we don't need to send a full RXON, we can use
- * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
- * and other flags for the current radio configuration. */
- if (!iwl_full_rxon_required(priv)) {
- rc = iwl3945_send_rxon_assoc(priv);
- if (rc) {
- IWL_ERR(priv, "Error setting RXON_ASSOC "
- "configuration (%d).\n", rc);
- return rc;
- }
-
- memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
-
- return 0;
- }
-
- /* If we are currently associated and the new config requires
- * an RXON_ASSOC and the new config wants the associated mask enabled,
- * we must clear the associated from the active configuration
- * before we apply the new config */
- if (iwl_is_associated(priv) && new_assoc) {
- IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
- active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
- /*
- * reserved4 and 5 could have been filled by the iwlcore code.
- * Let's clear them before pushing to the 3945.
- */
- active_rxon->reserved4 = 0;
- active_rxon->reserved5 = 0;
- rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl3945_rxon_cmd),
- &priv->active_rxon);
-
- /* If the mask clearing failed then we set
- * active_rxon back to what it was previously */
- if (rc) {
- active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
- IWL_ERR(priv, "Error clearing ASSOC_MSK on current "
- "configuration (%d).\n", rc);
- return rc;
- }
- }
-
- IWL_DEBUG_INFO(priv, "Sending RXON\n"
- "* with%s RXON_FILTER_ASSOC_MSK\n"
- "* channel = %d\n"
- "* bssid = %pM\n",
- (new_assoc ? "" : "out"),
- le16_to_cpu(staging_rxon->channel),
- staging_rxon->bssid_addr);
-
- /*
- * reserved4 and 5 could have been filled by the iwlcore code.
- * Let's clear them before pushing to the 3945.
- */
- staging_rxon->reserved4 = 0;
- staging_rxon->reserved5 = 0;
-
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
-
- /* Apply the new configuration */
- rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl3945_rxon_cmd),
- staging_rxon);
- if (rc) {
- IWL_ERR(priv, "Error setting new configuration (%d).\n", rc);
- return rc;
- }
-
- memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
-
- iwl3945_clear_stations_table(priv);
-
- /* If we issue a new RXON command which required a tune then we must
- * send a new TXPOWER command or we won't be able to Tx any frames */
- rc = priv->cfg->ops->lib->send_tx_power(priv);
- if (rc) {
- IWL_ERR(priv, "Error setting Tx power (%d).\n", rc);
- return rc;
- }
-
- /* Add the broadcast address so we can send broadcast frames */
- if (iwl3945_add_station(priv, iwl_bcast_addr, 0, 0) ==
- IWL_INVALID_STATION) {
- IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
- return -EIO;
- }
-
- /* If we have set the ASSOC_MSK and we are in BSS mode then
- * add the IWL_AP_ID to the station rate table */
- if (iwl_is_associated(priv) &&
- (priv->iw_mode == NL80211_IFTYPE_STATION))
- if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr,
- 1, 0)
- == IWL_INVALID_STATION) {
- IWL_ERR(priv, "Error adding AP address for transmit\n");
- return -EIO;
- }
-
- /* Init the hardware's rate fallback order based on the band */
- rc = iwl3945_init_hw_rate_table(priv);
- if (rc) {
- IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc);
- return -EIO;
- }
-
- return 0;
-}
-
static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
@@ -758,42 +570,6 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
le16_to_cpu(priv->rxon_timing.atim_window));
}
-static int iwl3945_set_mode(struct iwl_priv *priv, int mode)
-{
- if (mode == NL80211_IFTYPE_ADHOC) {
- const struct iwl_channel_info *ch_info;
-
- ch_info = iwl_get_channel_info(priv,
- priv->band,
- le16_to_cpu(priv->staging_rxon.channel));
-
- if (!ch_info || !is_channel_ibss(ch_info)) {
- IWL_ERR(priv, "channel %d not IBSS channel\n",
- le16_to_cpu(priv->staging_rxon.channel));
- return -EINVAL;
- }
- }
-
- iwl_connection_init_rx_config(priv, mode);
-
- iwl3945_clear_stations_table(priv);
-
- /* don't commit rxon if rf-kill is on*/
- if (!iwl_is_ready_rf(priv))
- return -EAGAIN;
-
- cancel_delayed_work(&priv->scan_check);
- if (iwl_scan_cancel_timeout(priv, 100)) {
- IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
- IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
- return -EAGAIN;
- }
-
- iwl3945_commit_rxon(priv);
-
- return 0;
-}
-
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
struct iwl_cmd *cmd,
@@ -900,64 +676,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx->next_frame_len = 0;
}
-/**
- * iwl3945_get_sta_id - Find station's index within station table
- */
-static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
-{
- int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- /* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
- return priv->hw_params.bcast_sta_id;
-
- switch (priv->iw_mode) {
-
- /* If we are a client station in a BSS network, use the special
- * AP station entry (that's the only station we communicate with) */
- case NL80211_IFTYPE_STATION:
- return IWL_AP_ID;
-
- /* If we are an AP, then find the station, or use BCAST */
- case NL80211_IFTYPE_AP:
- sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
- return priv->hw_params.bcast_sta_id;
-
- /* If this frame is going out to an IBSS network, find the station,
- * or create a new station table entry */
- case NL80211_IFTYPE_ADHOC: {
- /* Create new station table entry */
- sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
-
- sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
-
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
-
- IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
- "Defaulting to broadcast...\n",
- hdr->addr1);
- iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
- return priv->hw_params.bcast_sta_id;
- }
- /* If we are in monitor mode, use BCAST. This is required for
- * packet injection. */
- case NL80211_IFTYPE_MONITOR:
- return priv->hw_params.bcast_sta_id;
-
- default:
- IWL_WARN(priv, "Unknown mode of operation: %d\n",
- priv->iw_mode);
- return priv->hw_params.bcast_sta_id;
- }
-}
-
/*
* start REPLY_TX command process
*/
@@ -1011,7 +729,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* drop all data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */
+ (!iwl_is_monitor_mode(priv)) && /* packet injection */
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
@@ -1023,7 +741,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
- sta_id = iwl3945_get_sta_id(priv, hdr);
+ sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -1888,6 +1606,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
"r = %d, i = %d, %s, 0x%02x\n", r, i,
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
} else {
/* No handling needed */
IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR,
@@ -2129,9 +1848,9 @@ static void iwl3945_error_recovery(struct iwl_priv *priv)
memcpy(&priv->staging_rxon, &priv->recovery_rxon,
sizeof(priv->staging_rxon));
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
- iwl3945_add_station(priv, priv->bssid, 1, 0);
+ priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0, NULL);
spin_lock_irqsave(&priv->lock, flags);
priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
@@ -2187,6 +1906,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
+ priv->isr_stats.hw++;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_HW_ERR;
@@ -2199,13 +1919,17 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD)
+ if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
"the frame/frames.\n");
+ priv->isr_stats.sch++;
+ }
/* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE)
+ if (inta & CSR_INT_BIT_ALIVE) {
IWL_DEBUG_ISR(priv, "Alive interrupt\n");
+ priv->isr_stats.alive++;
+ }
}
#endif
/* Safely ignore these bits for debug checks below */
@@ -2215,6 +1939,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
if (inta & CSR_INT_BIT_SW_ERR) {
IWL_ERR(priv, "Microcode SW error detected. "
"Restarting 0x%X.\n", inta);
+ priv->isr_stats.sw++;
+ priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -2230,6 +1956,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_txq_update_write_ptr(priv, &priv->txq[4]);
iwl_txq_update_write_ptr(priv, &priv->txq[5]);
+ priv->isr_stats.wakeup++;
handled |= CSR_INT_BIT_WAKEUP;
}
@@ -2238,11 +1965,13 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
* notifications from uCode come through here*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
iwl3945_rx_handle(priv);
+ priv->isr_stats.rx++;
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
}
if (inta & CSR_INT_BIT_FH_TX) {
IWL_DEBUG_ISR(priv, "Tx interrupt\n");
+ priv->isr_stats.tx++;
iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
if (!iwl_grab_nic_access(priv)) {
@@ -2253,8 +1982,10 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_FH_TX;
}
- if (inta & ~handled)
+ if (inta & ~handled) {
IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+ priv->isr_stats.unhandled++;
+ }
if (inta & ~CSR_INI_SET_MASK) {
IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
@@ -2896,11 +2627,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv)
queue_work(priv->workqueue, &priv->restart);
}
-
-/* temporary */
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *skb);
-
/**
* iwl3945_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
@@ -2931,7 +2657,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
goto restart;
}
- iwl3945_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
rc = iwl_grab_nic_access(priv);
if (rc) {
@@ -2990,7 +2716,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl_send_bt_config(priv);
/* Configure the adapter for unassociated operation */
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
iwl3945_reg_txpower_periodic(priv);
@@ -3008,9 +2734,12 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
priv->vif);
if (beacon)
- iwl3945_mac_beacon_update(priv->hw, beacon);
+ iwl_mac_beacon_update(priv->hw, beacon);
}
+ if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
+ iwl_set_mode(priv, priv->iw_mode);
+
return;
restart:
@@ -3033,7 +2762,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
set_bit(STATUS_EXIT_PENDING, &priv->status);
iwl3945_led_unregister(priv);
- iwl3945_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
/* Unblock any waiting calls */
wake_up_interruptible_all(&priv->wait_command_queue);
@@ -3056,7 +2785,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
ieee80211_stop_queues(priv->hw);
/* If we have not previously called iwl3945_init() then
- * clear all bits but the RF Kill and SUSPEND bits and return */
+ * clear all bits but the RF Kill bits and return */
if (!iwl_is_init(priv)) {
priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
STATUS_RF_KILL_HW |
@@ -3064,23 +2793,19 @@ static void __iwl3945_down(struct iwl_priv *priv)
STATUS_RF_KILL_SW |
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
- test_bit(STATUS_IN_SUSPEND, &priv->status) <<
- STATUS_IN_SUSPEND |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
goto exit;
}
- /* ...otherwise clear out all the status bits but the RF Kill and
- * SUSPEND bits and continue taking the NIC down. */
+ /* ...otherwise clear out all the status bits but the RF Kill
+ * bits and continue taking the NIC down. */
priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
- test_bit(STATUS_IN_SUSPEND, &priv->status) <<
- STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
STATUS_FW_ERROR |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
@@ -3104,7 +2829,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
udelay(5);
- if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+ if (exit_pending)
priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv);
@@ -3157,10 +2882,8 @@ static int __iwl3945_up(struct iwl_priv *priv)
clear_bit(STATUS_RF_KILL_HW, &priv->status);
else {
set_bit(STATUS_RF_KILL_HW, &priv->status);
- if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
- IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
- return -ENODEV;
- }
+ IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
+ return -ENODEV;
}
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
@@ -3196,7 +2919,7 @@ static int __iwl3945_up(struct iwl_priv *priv)
for (i = 0; i < MAX_HW_RESTARTS; i++) {
- iwl3945_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
@@ -3292,9 +3015,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
int rc = 0;
struct iwl3945_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
- u8 n_probes = 2;
+ u8 n_probes = 0;
enum ieee80211_band band;
- DECLARE_SSID_BUF(ssid);
+ bool is_active = false;
conf = ieee80211_get_hw_conf(priv->hw);
@@ -3393,18 +3116,25 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
scan_suspend_time, interval);
}
- /* We should add the ability for user to lock to PASSIVE ONLY */
- if (priv->one_direct_scan) {
- IWL_DEBUG_SCAN(priv, "Kicking off one direct scan for '%s'\n",
- print_ssid(ssid, priv->direct_ssid,
- priv->direct_ssid_len));
- scan->direct_scan[0].id = WLAN_EID_SSID;
- scan->direct_scan[0].len = priv->direct_ssid_len;
- memcpy(scan->direct_scan[0].ssid,
- priv->direct_ssid, priv->direct_ssid_len);
- n_probes++;
+ if (priv->scan_request->n_ssids) {
+ int i, p = 0;
+ IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ /* always does wildcard anyway */
+ if (!priv->scan_request->ssids[i].ssid_len)
+ continue;
+ scan->direct_scan[p].id = WLAN_EID_SSID;
+ scan->direct_scan[p].len =
+ priv->scan_request->ssids[i].ssid_len;
+ memcpy(scan->direct_scan[p].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ n_probes++;
+ p++;
+ }
+ is_active = true;
} else
- IWL_DEBUG_SCAN(priv, "Kicking off one indirect scan.\n");
+ IWL_DEBUG_SCAN(priv, "Kicking off passive scan.\n");
/* We don't build a direct scan probe request; the uCode will do
* that based on the direct_mask added to each channel entry */
@@ -3421,7 +3151,12 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
band = IEEE80211_BAND_2GHZ;
} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
- scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ /*
+ * If active scaning is requested but a certain channel
+ * is marked passive, we can do active scanning if we
+ * detect transmissions.
+ */
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
band = IEEE80211_BAND_5GHZ;
} else {
IWL_WARN(priv, "Invalid scan band count\n");
@@ -3429,19 +3164,20 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
}
scan->tx_cmd.len = cpu_to_le16(
- iwl_fill_probe_req(priv, band,
- (struct ieee80211_mgmt *)scan->data,
- IWL_MAX_SCAN_SIZE - sizeof(*scan)));
+ iwl_fill_probe_req(priv,
+ (struct ieee80211_mgmt *)scan->data,
+ priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan)));
/* select Rx antennas */
scan->flags |= iwl3945_get_antenna_flags(priv);
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
+ if (iwl_is_monitor_mode(priv))
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
scan->channel_count =
- iwl3945_get_channels_for_scan(priv, band, 1, /* active */
- n_probes,
+ iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
if (scan->channel_count == 0) {
@@ -3518,7 +3254,7 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static void iwl3945_post_associate(struct iwl_priv *priv)
+void iwl3945_post_associate(struct iwl_priv *priv)
{
int rc = 0;
struct ieee80211_conf *conf = NULL;
@@ -3543,7 +3279,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv)
conf = ieee80211_get_hw_conf(priv->hw);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
iwl3945_setup_rxon_timing(priv);
@@ -3576,7 +3312,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv)
}
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
switch (priv->iw_mode) {
case NL80211_IFTYPE_STATION:
@@ -3586,7 +3322,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv)
case NL80211_IFTYPE_ADHOC:
priv->assoc_id = 1;
- iwl3945_add_station(priv, priv->bssid, 0, 0);
+ priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL);
iwl3945_sync_sta(priv, IWL_STA_ID,
(priv->band == IEEE80211_BAND_5GHZ) ?
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
@@ -3608,8 +3344,6 @@ static void iwl3945_post_associate(struct iwl_priv *priv)
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
}
-static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed);
-
/*****************************************************************************
*
* mac80211 entry point functions
@@ -3652,9 +3386,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
IWL_DEBUG_INFO(priv, "Start UP work.\n");
- if (test_bit(STATUS_IN_SUSPEND, &priv->status))
- return 0;
-
/* Wait for START_ALIVE from ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
@@ -3733,144 +3464,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
-
- IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
-
- if (priv->vif) {
- IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
- return -EOPNOTSUPP;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->vif = conf->vif;
- priv->iw_mode = conf->type;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- mutex_lock(&priv->mutex);
-
- if (conf->mac_addr) {
- IWL_DEBUG_MAC80211(priv, "Set: %pM\n", conf->mac_addr);
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- }
-
- if (iwl_is_ready(priv))
- iwl3945_set_mode(priv, conf->type);
-
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
-}
-
-/**
- * iwl3945_mac_config - mac80211 config callback
- *
- * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
- * be set inappropriately and the driver currently sets the hardware up to
- * use it whenever needed.
- */
-static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct iwl_priv *priv = hw->priv;
- const struct iwl_channel_info *ch_info;
- struct ieee80211_conf *conf = &hw->conf;
- unsigned long flags;
- int ret = 0;
-
- mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211(priv, "enter to channel %d\n",
- conf->channel->hw_value);
-
- if (!iwl_is_ready(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- ret = -EIO;
- goto out;
- }
-
- if (unlikely(!iwl3945_mod_params.disable_hw_scan &&
- test_bit(STATUS_SCANNING, &priv->status))) {
- IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
- set_bit(STATUS_CONF_PENDING, &priv->status);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- ch_info = iwl_get_channel_info(priv, conf->channel->band,
- conf->channel->hw_value);
- if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN(priv,
- "Channel %d [%d] is INVALID for this band.\n",
- conf->channel->hw_value, conf->channel->band);
- IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
- spin_unlock_irqrestore(&priv->lock, flags);
- ret = -EINVAL;
- goto out;
- }
-
- iwl_set_rxon_channel(priv, conf->channel);
-
- iwl_set_flags_for_band(priv, conf->channel->band);
-
- /* The list of supported rates and rate mask can be different
- * for each phymode; since the phymode may have changed, reset
- * the rate mask to what mac80211 lists */
- iwl_set_rate(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
-#ifdef IEEE80211_CONF_CHANNEL_SWITCH
- if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
- iwl3945_hw_channel_switch(priv, conf->channel);
- goto out;
- }
-#endif
-
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- if (conf->radio_enabled &&
- iwl_radio_kill_sw_enable_radio(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - "
- "waiting for uCode\n");
- goto out;
- }
-
- if (!conf->radio_enabled) {
- iwl_radio_kill_sw_disable_radio(priv);
- IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
- goto out;
- }
- }
-
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF kill\n");
- ret = -EIO;
- goto out;
- }
-
- iwl_set_rate(priv);
-
- if (memcmp(&priv->active_rxon,
- &priv->staging_rxon, sizeof(priv->staging_rxon)))
- iwl3945_commit_rxon(priv);
- else
- IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration\n");
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
-out:
- clear_bit(STATUS_CONF_PENDING, &priv->status);
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static void iwl3945_config_ap(struct iwl_priv *priv)
+void iwl3945_config_ap(struct iwl_priv *priv)
{
int rc = 0;
@@ -3882,7 +3476,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv)
/* RXON - unassoc (to set timing command) */
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
/* RXON Timing */
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
@@ -3918,8 +3512,8 @@ static void iwl3945_config_ap(struct iwl_priv *priv)
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
- iwl3945_add_station(priv, iwl_bcast_addr, 0, 0);
+ iwlcore_commit_rxon(priv);
+ priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL);
}
iwl3945_send_beacon_cmd(priv);
@@ -3928,189 +3522,6 @@ static void iwl3945_config_ap(struct iwl_priv *priv)
* clear sta table, add BCAST sta... */
}
-static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_if_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
- int rc;
-
- if (conf == NULL)
- return -EIO;
-
- if (priv->vif != vif) {
- IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n");
- return 0;
- }
-
- /* handle this temporarily here */
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
- conf->changed & IEEE80211_IFCC_BEACON) {
- struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
- if (!beacon)
- return -ENOMEM;
- mutex_lock(&priv->mutex);
- rc = iwl3945_mac_beacon_update(hw, beacon);
- mutex_unlock(&priv->mutex);
- if (rc)
- return rc;
- }
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- mutex_lock(&priv->mutex);
-
- if (conf->bssid)
- IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid);
-
-/*
- * very dubious code was here; the probe filtering flag is never set:
- *
- if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
- !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
- */
-
- if (priv->iw_mode == NL80211_IFTYPE_AP) {
- if (!conf->bssid) {
- conf->bssid = priv->mac_addr;
- memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
- IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n",
- conf->bssid);
- }
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
- }
-
- if (iwl_is_rfkill(priv))
- goto done;
-
- if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
- !is_multicast_ether_addr(conf->bssid)) {
- /* If there is currently a HW scan going on in the background
- * then we need to cancel it else the RXON below will fail. */
- if (iwl_scan_cancel_timeout(priv, 100)) {
- IWL_WARN(priv, "Aborted scan still in progress "
- "after 100ms\n");
- IWL_DEBUG_MAC80211(priv, "leaving:scan abort failed\n");
- mutex_unlock(&priv->mutex);
- return -EAGAIN;
- }
- memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
-
- /* TODO: Audit driver for usage of these members and see
- * if mac80211 deprecates them (priv->bssid looks like it
- * shouldn't be there, but I haven't scanned the IBSS code
- * to verify) - jpk */
- memcpy(priv->bssid, conf->bssid, ETH_ALEN);
-
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl3945_config_ap(priv);
- else {
- rc = iwl3945_commit_rxon(priv);
- if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
- iwl3945_add_station(priv,
- priv->active_rxon.bssid_addr, 1, 0);
- }
-
- } else {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
- }
-
- done:
- IWL_DEBUG_MAC80211(priv, "leave\n");
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct iwl_priv *priv = hw->priv;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- mutex_lock(&priv->mutex);
-
- if (iwl_is_ready_rf(priv)) {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
- }
- if (priv->vif == conf->vif) {
- priv->vif = NULL;
- memset(priv->bssid, 0, ETH_ALEN);
- }
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
-
-static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes)
-{
- struct iwl_priv *priv = hw->priv;
-
- IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
-
- if (changes & BSS_CHANGED_ERP_PREAMBLE) {
- IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
- bss_conf->use_short_preamble);
- if (bss_conf->use_short_preamble)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
- else
- priv->staging_rxon.flags &=
- ~RXON_FLG_SHORT_PREAMBLE_MSK;
- }
-
- if (changes & BSS_CHANGED_ERP_CTS_PROT) {
- IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n",
- bss_conf->use_cts_prot);
- if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
- priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
- else
- priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
- }
-
- if (changes & BSS_CHANGED_ASSOC) {
- IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
- /* This should never happen as this function should
- * never be called from interrupt context. */
- if (WARN_ON_ONCE(in_interrupt()))
- return;
- if (bss_conf->assoc) {
- priv->assoc_id = bss_conf->aid;
- priv->beacon_int = bss_conf->beacon_int;
- priv->timestamp = bss_conf->timestamp;
- priv->assoc_capability = bss_conf->assoc_capability;
- priv->power_data.dtim_period = bss_conf->dtim_period;
- priv->next_scan_jiffies = jiffies +
- IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
- mutex_lock(&priv->mutex);
- iwl3945_post_associate(priv);
- mutex_unlock(&priv->mutex);
- } else {
- priv->assoc_id = 0;
- IWL_DEBUG_MAC80211(priv,
- "DISASSOC %d\n", bss_conf->assoc);
- }
- } else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
- IWL_DEBUG_MAC80211(priv,
- "Associated Changes %d\n", changes);
- iwl3945_send_rxon_assoc(priv);
- }
-
-}
-
static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -4133,7 +3544,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
static_key = !iwl_is_associated(priv);
if (!static_key) {
- sta_id = iwl3945_hw_find_station(priv, addr);
+ sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@@ -4169,185 +3580,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- int q;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- if (queue >= AC_NUM) {
- IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
- return 0;
- }
-
- q = AC_NUM - 1 - queue;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
- priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
- priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
- priv->qos_data.def_qos_parm.ac[q].edca_txop =
- cpu_to_le16((params->txop * 32));
-
- priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
- priv->qos_data.qos_active = 1;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- mutex_lock(&priv->mutex);
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl_activate_qos(priv, 1);
- else if (priv->assoc_id && iwl_is_associated(priv))
- iwl_activate_qos(priv, 0);
-
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
-}
-
-static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct iwl_priv *priv = hw->priv;
- int i, avail;
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- unsigned long flags;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- for (i = 0; i < AC_NUM; i++) {
- txq = &priv->txq[i];
- q = &txq->q;
- avail = iwl_queue_space(q);
-
- stats[i].len = q->n_window - avail;
- stats[i].limit = q->n_window - q->high_mark;
- stats[i].count = q->n_window;
-
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
- return 0;
-}
-
-static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
-
- mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- iwl_reset_qos(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->assoc_id = 0;
- priv->assoc_capability = 0;
-
- /* new association get rid of ibss beacon skb */
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = NULL;
-
- priv->beacon_int = priv->hw->conf.beacon_int;
- priv->timestamp = 0;
- if ((priv->iw_mode == NL80211_IFTYPE_STATION))
- priv->beacon_int = 0;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
- /* we are restarting association process
- * clear RXON_FILTER_ASSOC_MSK bit
- */
- if (priv->iw_mode != NL80211_IFTYPE_AP) {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
- }
-
- /* Per mac80211.h: This is only used in IBSS mode... */
- if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-
- IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
- iwl_set_rate(priv);
-
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
-
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- __le64 timestamp;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
- IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = skb;
-
- priv->assoc_id = 0;
- timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- spin_unlock_irqrestore(&priv->lock, flags);
-
- iwl_reset_qos(priv);
-
- iwl3945_post_associate(priv);
-
-
- return 0;
-}
-
/*****************************************************************************
*
* sysfs attributes
@@ -4455,7 +3687,7 @@ static ssize_t store_flags(struct device *d,
IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",
flags);
priv->staging_rxon.flags = cpu_to_le32(flags);
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -4491,7 +3723,7 @@ static ssize_t store_filter_flags(struct device *d,
"0x%04X\n", filter_flags);
priv->staging_rxon.filter_flags =
cpu_to_le32(filter_flags);
- iwl3945_commit_rxon(priv);
+ iwlcore_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -4871,16 +4103,16 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.tx = iwl3945_mac_tx,
.start = iwl3945_mac_start,
.stop = iwl3945_mac_stop,
- .add_interface = iwl3945_mac_add_interface,
- .remove_interface = iwl3945_mac_remove_interface,
- .config = iwl3945_mac_config,
- .config_interface = iwl3945_mac_config_interface,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
.configure_filter = iwl_configure_filter,
.set_key = iwl3945_mac_set_key,
- .get_tx_stats = iwl3945_mac_get_tx_stats,
- .conf_tx = iwl3945_mac_conf_tx,
- .reset_tsf = iwl3945_mac_reset_tsf,
- .bss_info_changed = iwl3945_bss_info_changed,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .bss_info_changed = iwl_bss_info_changed,
.hw_scan = iwl_mac_hw_scan
};
@@ -4902,7 +4134,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
mutex_init(&priv->mutex);
/* Clear the driver's (not device's) station table */
- iwl3945_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
@@ -4973,7 +4205,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
hw->wiphy->custom_regulatory = true;
- hw->wiphy->max_scan_ssids = 1; /* WILL FIX */
+ hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
+ /* we create the 802.11 header and a zero-length SSID element */
+ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
@@ -5135,20 +4369,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s\n",
priv->cfg->name);
- /***********************************
- * 7. Initialize Module Parameters
- * **********************************/
-
- /* Initialize module parameter values here */
- /* Disable radio (SW RF KILL) via parameter when loading driver */
- if (iwl3945_mod_params.disable) {
- set_bit(STATUS_RF_KILL_SW, &priv->status);
- IWL_DEBUG_INFO(priv, "Radio disabled.\n");
- }
-
-
/***********************
- * 8. Setup Services
+ * 7. Setup Services
* ********************/
spin_lock_irqsave(&priv->lock, flags);
@@ -5176,7 +4398,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
iwl3945_setup_rx_handlers(priv);
/*********************************
- * 9. Setup and Register mac80211
+ * 8. Setup and Register mac80211
* *******************************/
iwl_enable_interrupts(priv);
@@ -5185,6 +4407,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (err)
goto out_remove_sysfs;
+ err = iwl_dbgfs_register(priv, DRV_NAME);
+ if (err)
+ IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
+
err = iwl_rfkill_init(priv);
if (err)
IWL_ERR(priv, "Unable to initialize RFKILL system. "
@@ -5235,6 +4461,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
+ iwl_dbgfs_unregister(priv);
+
set_bit(STATUS_EXIT_PENDING, &priv->status);
if (priv->mac80211_registered) {
@@ -5265,7 +4493,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_hw_txq_ctx_free(priv);
iwl3945_unset_hw_params(priv);
- iwl3945_clear_stations_table(priv);
+ priv->cfg->ops->smgmt->clear_station_table(priv);
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
@@ -5293,43 +4521,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
ieee80211_free_hw(priv->hw);
}
-#ifdef CONFIG_PM
-
-static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
-
- if (priv->is_open) {
- set_bit(STATUS_IN_SUSPEND, &priv->status);
- iwl3945_mac_stop(priv->hw);
- priv->is_open = 1;
- }
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-static int iwl3945_pci_resume(struct pci_dev *pdev)
-{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
- int ret;
-
- pci_set_power_state(pdev, PCI_D0);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
- pci_restore_state(pdev);
-
- if (priv->is_open)
- iwl3945_mac_start(priv->hw);
-
- clear_bit(STATUS_IN_SUSPEND, &priv->status);
- return 0;
-}
-
-#endif /* CONFIG_PM */
/*****************************************************************************
*
@@ -5343,8 +4534,8 @@ static struct pci_driver iwl3945_driver = {
.probe = iwl3945_pci_probe,
.remove = __devexit_p(iwl3945_pci_remove),
#ifdef CONFIG_PM
- .suspend = iwl3945_pci_suspend,
- .resume = iwl3945_pci_resume,
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
#endif
};
@@ -5385,8 +4576,6 @@ MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(disable, iwl3945_mod_params.disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 8c3605cdc64..c455b9abbfc 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -119,6 +119,19 @@ int lbs_update_hw_spec(struct lbs_private *priv)
lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
cmd.hwifversion, cmd.version);
+ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+ /* 5.110.22 have mesh command with 0xa3 command id */
+ /* 10.0.0.p0 FW brings in mesh config command with different id */
+ /* Check FW version MSB and initialize mesh_fw_ver */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+ priv->mesh_fw_ver = MESH_FW_OLD;
+ else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
+ priv->mesh_fw_ver = MESH_FW_NEW;
+ else
+ priv->mesh_fw_ver = MESH_NONE;
+
/* Clamp region code to 8-bit since FW spec indicates that it should
* only ever be 8-bit, even though the field size is 16-bit. Some firmware
* returns non-zero high 8 bits here.
@@ -1036,17 +1049,26 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
uint16_t action, uint16_t type)
{
int ret;
+ u16 command = CMD_MESH_CONFIG_OLD;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
+ /*
+ * Command id is 0xac for v10 FW along with mesh interface
+ * id in bits 14-13-12.
+ */
+ if (priv->mesh_fw_ver == MESH_FW_NEW)
+ command = CMD_MESH_CONFIG |
+ (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
+
+ cmd->hdr.command = cpu_to_le16(command);
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
cmd->hdr.result = 0;
cmd->type = cpu_to_le16(type);
cmd->action = cpu_to_le16(action);
- ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
+ ret = lbs_cmd_with_response(priv, command, cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index e8dfde39abf..48da157d6cd 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -227,6 +227,20 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define TxPD_CONTROL_WDS_FRAME (1<<17)
#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+/** Mesh interface ID */
+#define MESH_IFACE_ID 0x0001
+/** Mesh id should be in bits 14-13-12 */
+#define MESH_IFACE_BIT_OFFSET 0x000c
+/** Mesh enable bit in FW capability */
+#define MESH_CAPINFO_ENABLE_MASK (1<<16)
+
+/** FW definition from Marvell v5 */
+#define MRVL_FW_V5 (0x05)
+/** FW definition from Marvell v10 */
+#define MRVL_FW_V10 (0x0a)
+/** FW major revision definition */
+#define MRVL_FW_MAJOR_REV(x) ((x)>>24)
+
/** RxPD status */
#define MRVDRV_RXPD_STATUS_OK 0x0001
@@ -380,6 +394,13 @@ enum KEY_INFO_WPA {
KEY_INFO_WPA_ENABLED = 0x04
};
+/** mesh_fw_ver */
+enum _mesh_fw_ver {
+ MESH_NONE = 0, /* MESH is not supported */
+ MESH_FW_OLD, /* MESH is supported in FW V5 */
+ MESH_FW_NEW, /* MESH is supported in FW V10 and newer */
+};
+
/* Default values for fwt commands. */
#define FWT_DEFAULT_METRIC 0
#define FWT_DEFAULT_DIR 1
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 27e81fd97c9..cbaafa653b6 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -101,6 +101,7 @@ struct lbs_mesh_stats {
/** Private structure for the MV device */
struct lbs_private {
int mesh_open;
+ int mesh_fw_ver;
int infra_open;
int mesh_autostart_enabled;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index d4457ef808a..8ff8ac9d817 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -83,7 +83,8 @@
#define CMD_FWT_ACCESS 0x0095
#define CMD_802_11_MONITOR_MODE 0x0098
#define CMD_MESH_ACCESS 0x009b
-#define CMD_MESH_CONFIG 0x00a3
+#define CMD_MESH_CONFIG_OLD 0x00a3
+#define CMD_MESH_CONFIG 0x00ac
#define CMD_SET_BOOT2_VER 0x00a5
#define CMD_802_11_BEACON_CTRL 0x00b0
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index a899aeb676b..391c54ab2b0 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -13,8 +13,19 @@
/* TxPD descriptor */
struct txpd {
- /* Current Tx packet status */
- __le32 tx_status;
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Tx packet status */
+ __le32 tx_status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ /* Reserved */
+ __le16 reserved;
+ } bss;
+ } u;
/* Tx control */
__le32 tx_control;
__le32 tx_packet_location;
@@ -36,8 +47,17 @@ struct txpd {
/* RxPD Descriptor */
struct rxpd {
- /* Current Rx packet status */
- __le16 status;
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Rx packet status */
+ __le16 status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ } bss;
+ } u;
/* SNR */
u8 snr;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index cedeac6322f..2a5b083bf9b 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -273,7 +273,28 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
*/
#define IF_CS_PRODUCT_ID 0x0000001C
#define IF_CS_CF8385_B1_REV 0x12
+#define IF_CS_CF8381_B3_REV 0x04
+/*
+ * Used to detect other cards than CF8385 since their revisions of silicon
+ * doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
+ */
+#define CF8381_MANFID 0x02db
+#define CF8381_CARDID 0x6064
+#define CF8385_MANFID 0x02df
+#define CF8385_CARDID 0x8103
+
+static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
+{
+ return (p_dev->manf_id == CF8381_MANFID &&
+ p_dev->card_id == CF8381_CARDID);
+}
+
+static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev)
+{
+ return (p_dev->manf_id == CF8385_MANFID &&
+ p_dev->card_id == CF8385_CARDID);
+}
/********************************************************************/
/* I/O and interrupt handling */
@@ -757,6 +778,7 @@ static void if_cs_release(struct pcmcia_device *p_dev)
static int if_cs_probe(struct pcmcia_device *p_dev)
{
int ret = -ENOMEM;
+ unsigned int prod_id;
struct lbs_private *priv;
struct if_cs_card *card;
/* CIS parsing */
@@ -859,7 +881,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
/* Check if we have a current silicon */
- if (if_cs_read8(card, IF_CS_PRODUCT_ID) < IF_CS_CF8385_B1_REV) {
+ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
+ if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
+ lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
+ ret = -ENODEV;
+ goto out2;
+ }
+
+ if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) {
lbs_pr_err("old chips like 8385 rev B1 aren't supported\n");
ret = -ENODEV;
goto out2;
@@ -950,7 +979,8 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
/********************************************************************/
static struct pcmcia_device_id if_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
+ PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
+ PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 76f4c653d64..55864c10f9f 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -48,8 +48,11 @@ static char *lbs_fw_name = NULL;
module_param_named(fw_name, lbs_fw_name, charp, 0644);
static const struct sdio_device_id if_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
- { /* end: all zeroes */ },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+ SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+ SDIO_DEVICE_ID_MARVELL_8688WLAN) },
+ { /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
@@ -73,6 +76,12 @@ static struct if_sdio_model if_sdio_models[] = {
.helper = "sd8686_helper.bin",
.firmware = "sd8686.bin",
},
+ {
+ /* 8688 */
+ .model = 0x10,
+ .helper = "sd8688_helper.bin",
+ .firmware = "sd8688.bin",
+ },
};
struct if_sdio_packet {
@@ -488,7 +497,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
ret = 0;
release:
- sdio_set_block_size(card->func, 0);
+ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
sdio_release_host(card->func);
kfree(chunk_buffer);
release_fw:
@@ -624,7 +633,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
ret = 0;
release:
- sdio_set_block_size(card->func, 0);
+ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
sdio_release_host(card->func);
kfree(chunk_buffer);
release_fw:
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 533bdfbf5d2..37ada2c29aa 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -42,4 +42,6 @@
#define IF_SDIO_EVENT 0x80fc
+#define IF_SDIO_BLOCK_SIZE 256
+
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 07311e71af9..dccd01fd1f1 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -731,7 +731,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %u\n",
+ "our maximum skb size is %lu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -1020,6 +1020,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
int err = 0;
u32 scratch;
+ struct sched_param param = { .sched_priority = 1 };
lbs_deb_enter(LBS_DEB_SPI);
@@ -1123,6 +1124,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
lbs_pr_err("error creating SPI thread: err=%d\n", err);
goto remove_card;
}
+ if (sched_setscheduler(card->spi_thread, SCHED_FIFO, &param))
+ lbs_pr_err("Error setting scheduler, using default.\n");
+
err = request_irq(spi->irq, if_spi_host_interrupt,
IRQF_TRIGGER_FALLING, "libertas_spi", card);
if (err) {
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 8ae935ac32f..89575e44801 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1307,8 +1307,10 @@ int lbs_start_card(struct lbs_private *priv)
lbs_update_channel(priv);
- /* 5.0.16p0 is known to NOT support any mesh */
- if (priv->fwrelease > 0x05001000) {
+ /* Check mesh FW version and appropriately send the mesh start
+ * command
+ */
+ if (priv->mesh_fw_ver == MESH_FW_OLD) {
/* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110.20.pXX
0x100 + 37 is the official value used in 5.110.21.pXX
@@ -1322,27 +1324,35 @@ int lbs_start_card(struct lbs_private *priv)
It's just that 5.110.20.pXX will not have done anything
useful */
- priv->mesh_tlv = 0x100 + 291;
+ priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) {
- priv->mesh_tlv = 0x100 + 37;
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel))
priv->mesh_tlv = 0;
}
- if (priv->mesh_tlv) {
- lbs_add_mesh(priv);
-
- if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- lbs_pr_err("cannot register lbs_mesh attribute\n");
-
- /* While rtap isn't related to mesh, only mesh-enabled
- * firmware implements the rtap functionality via
- * CMD_802_11_MONITOR_MODE.
- */
- if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
- lbs_pr_err("cannot register lbs_rtap attribute\n");
- }
+ } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ /* 10.0.0.pXX new firmwares should succeed with TLV
+ * 0x100+37; Do not invoke command with old TLV.
+ */
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->curbssparams.channel))
+ priv->mesh_tlv = 0;
+ }
+ if (priv->mesh_tlv) {
+ lbs_add_mesh(priv);
+
+ if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
+ lbs_pr_err("cannot register lbs_mesh attribute\n");
+
+ /* While rtap isn't related to mesh, only mesh-enabled
+ * firmware implements the rtap functionality via
+ * CMD_802_11_MONITOR_MODE.
+ */
+ if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
+ lbs_pr_err("cannot register lbs_rtap attribute\n");
}
lbs_debugfs_init_one(priv, dev);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 8e669775cb5..65f02cc6752 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -25,7 +25,6 @@ struct rfc1042hdr {
} __attribute__ ((packed));
struct rxpackethdr {
- struct rxpd rx_pd;
struct eth803hdr eth803_hdr;
struct rfc1042hdr rfc1042_hdr;
} __attribute__ ((packed));
@@ -158,10 +157,18 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
if (priv->monitormode)
return process_rxed_802_11_packet(priv, skb);
- p_rx_pkt = (struct rxpackethdr *) skb->data;
- p_rx_pd = &p_rx_pkt->rx_pd;
- if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME))
- dev = priv->mesh_dev;
+ p_rx_pd = (struct rxpd *) skb->data;
+ p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
+ le32_to_cpu(p_rx_pd->pkt_ptr));
+ if (priv->mesh_dev) {
+ if (priv->mesh_fw_ver == MESH_FW_OLD) {
+ if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+ dev = priv->mesh_dev;
+ } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID)
+ dev = priv->mesh_dev;
+ }
+ }
lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
min_t(unsigned int, skb->len, 100));
@@ -174,20 +181,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
goto done;
}
- /*
- * Check rxpd status and update 802.3 stat,
- */
- if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
- lbs_deb_rx("rx err: frame received with bad status\n");
- lbs_pr_alert("rxpd not ok\n");
- dev->stats.rx_errors++;
- ret = 0;
- dev_kfree_skb(skb);
- goto done;
- }
-
- lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
- skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+ lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n",
+ skb->len, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr),
+ skb->len - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr));
lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
sizeof(p_rx_pkt->eth803_hdr.dest_addr));
@@ -221,14 +217,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
/* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
* that was removed
*/
- hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+ hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd;
} else {
lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
(u8 *) & p_rx_pkt->rfc1042_hdr,
sizeof(p_rx_pkt->rfc1042_hdr));
/* Chop off the rxpd */
- hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+ hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd;
}
/* Chop off the leading header bytes so the skb points to the start of
@@ -334,14 +330,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
goto done;
}
- /*
- * Check rxpd status and update 802.3 stat,
- */
- if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
- //lbs_deb_rx("rx err: frame received with bad status\n");
- dev->stats.rx_errors++;
- }
-
lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
@@ -353,8 +341,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
radiotap_hdr.hdr.it_pad = 0;
radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
- if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
- radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS;
radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
/* XXX must check no carryout */
radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index f10aa39a6b6..160cfd8311c 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -132,8 +132,12 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
txpd->tx_packet_length = cpu_to_le16(pkt_len);
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
- if (dev == priv->mesh_dev)
- txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
+ if (dev == priv->mesh_dev) {
+ if (priv->mesh_fw_ver == MESH_FW_OLD)
+ txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
+ else if (priv->mesh_fw_ver == MESH_FW_NEW)
+ txpd->u.bss.bss_num = MESH_IFACE_ID;
+ }
lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index fb7a2d1a252..de03b9c9c20 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -94,6 +94,8 @@ struct ieeetypes_assocrsp {
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
+#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
+#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
/** TLV related data structures*/
struct mrvlietypesheader {
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index ecf8b6ed5a4..7fda1a9e263 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -125,6 +125,7 @@ struct p54_led_dev {
struct led_classdev led_dev;
char name[P54_LED_MAX_NAME_LEN + 1];
+ unsigned int toggled;
unsigned int index;
unsigned int registered;
};
@@ -133,55 +134,74 @@ struct p54_led_dev {
struct p54_common {
struct ieee80211_hw *hw;
- u32 rx_start;
- u32 rx_end;
- struct sk_buff_head tx_queue;
+ struct ieee80211_vif *vif;
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
- int mode;
+ struct sk_buff_head tx_queue;
+ struct mutex conf_mutex;
+
+ /* memory management (as seen by the firmware) */
+ u32 rx_start;
+ u32 rx_end;
u16 rx_mtu;
u8 headroom;
u8 tailroom;
- struct mutex conf_mutex;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
+
+ /* firmware/hardware info */
+ unsigned int tx_hdr_len;
+ unsigned int fw_var;
+ unsigned int fw_interface;
+ u8 version;
+
+ /* (e)DCF / QOS state */
+ bool use_short_slot;
+ struct ieee80211_tx_queue_stats tx_stats[8];
+ struct p54_edcf_queue_param qos_params[8];
+
+ /* Radio data */
+ u16 rxhw;
u8 rx_diversity_mask;
u8 tx_diversity_mask;
+ unsigned int output_power;
+ int noise;
+ /* calibration, output power limit and rssi<->dBm conversation data */
struct pda_iq_autocal_entry *iq_autocal;
unsigned int iq_autocal_len;
- struct p54_cal_database *output_limit;
struct p54_cal_database *curve_data;
+ struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+
+ /* BBP/MAC state */
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u16 wakeup_timer;
unsigned int filter_flags;
- bool use_short_slot;
- u16 rxhw;
- u8 version;
- unsigned int tx_hdr_len;
- unsigned int fw_var;
- unsigned int fw_interface;
- unsigned int output_power;
- u32 tsf_low32;
- u32 tsf_high32;
+ int mode;
+ u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
- u16 wakeup_timer;
u16 aid;
- struct ieee80211_tx_queue_stats tx_stats[8];
- struct p54_edcf_queue_param qos_params[8];
- struct ieee80211_low_level_stats stats;
- struct delayed_work work;
struct sk_buff *cached_beacon;
- int noise;
- void *eeprom;
- struct completion eeprom_comp;
+
+ /* cryptographic engine information */
u8 privacy_caps;
u8 rx_keycache_size;
+ unsigned long *used_rxkeys;
+
/* LED management */
-#ifdef CONFIG_P54_LEDS
- struct p54_led_dev assoc_led;
- struct p54_led_dev tx_led;
-#endif /* CONFIG_P54_LEDS */
+#ifdef CONFIG_MAC80211_LEDS
+ struct p54_led_dev leds[4];
+ struct delayed_work led_work;
+#endif /* CONFIG_MAC80211_LEDS */
u16 softled_state; /* bit field of glowing LEDs */
+
+ /* statistics */
+ struct ieee80211_low_level_stats stats;
+ struct delayed_work work;
+
+ /* eeprom handling */
+ void *eeprom;
+ struct completion eeprom_comp;
};
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index c8f0232ee5e..71394968d45 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
dev->queues = P54_QUEUE_AC_NUM;
}
- if (!modparam_nohwcrypt)
+ if (!modparam_nohwcrypt) {
printk(KERN_INFO "%s: cryptographic accelerator "
"WEP:%s, TKIP:%s, CCMP:%s\n",
wiphy_name(dev->wiphy),
@@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
"YES" : "no");
+ if (priv->rx_keycache_size) {
+ /*
+ * NOTE:
+ *
+ * The firmware provides at most 255 (0 - 254) slots
+ * for keys which are then used to offload decryption.
+ * As a result the 255 entry (aka 0xff) can be used
+ * safely by the driver to mark keys that didn't fit
+ * into the full cache. This trick saves us from
+ * keeping a extra list for uploaded keys.
+ */
+
+ priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+ priv->rx_keycache_size), GFP_KERNEL);
+
+ if (!priv->used_rxkeys)
+ return -ENOMEM;
+ }
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(p54_parse_firmware);
@@ -749,8 +769,6 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
rx_status.noise = priv->noise;
- /* XX correct? */
- rx_status.qual = (100 * hdr->rssi) / 127;
if (hdr->rate & 0x10)
rx_status.flag |= RX_FLAG_SHORTPRE;
if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
@@ -1044,6 +1062,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
{
+ struct p54_common *priv = dev->priv;
struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
struct p54_trap *trap = (struct p54_trap *) hdr->data;
u16 event = le16_to_cpu(trap->event);
@@ -1057,6 +1076,8 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
wiphy_name(dev->wiphy), freq);
break;
case P54_TRAP_NO_BEACON:
+ if (priv->vif)
+ ieee80211_beacon_loss(priv->vif);
break;
case P54_TRAP_SCAN:
break;
@@ -1452,7 +1473,8 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
if (info->control.sta)
*aid = info->control.sta->aid;
- else
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
break;
}
@@ -1939,7 +1961,8 @@ static int p54_set_ps(struct ieee80211_hw *dev)
int i;
if (dev->conf.flags & IEEE80211_CONF_PS)
- mode = P54_PSM | P54_PSM_DTIM | P54_PSM_MCBC;
+ mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+ P54_PSM_CHECKSUM | P54_PSM_MCBC;
else
mode = P54_PSM_CAM;
@@ -1957,9 +1980,10 @@ static int p54_set_ps(struct ieee80211_hw *dev)
psm->intervals[i].periods = cpu_to_le16(1);
}
- psm->beacon_rssi_skip_max = 60;
+ psm->beacon_rssi_skip_max = 200;
psm->rssi_delta_threshold = 0;
- psm->nr = 0;
+ psm->nr = 10;
+ psm->exclude[0] = 0;
priv->tx(dev, skb);
@@ -2088,6 +2112,9 @@ static void p54_stop(struct ieee80211_hw *dev)
priv->softled_state = 0;
p54_set_leds(dev);
+#ifdef CONFIG_P54_LEDS
+ cancel_delayed_work_sync(&priv->led_work);
+#endif /* CONFIG_P54_LEDS */
cancel_delayed_work_sync(&priv->work);
if (priv->cached_beacon)
p54_tx_cancel(dev, priv->cached_beacon);
@@ -2111,6 +2138,8 @@ static int p54_add_interface(struct ieee80211_hw *dev,
return -EOPNOTSUPP;
}
+ priv->vif = conf->vif;
+
switch (conf->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
@@ -2135,6 +2164,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
struct p54_common *priv = dev->priv;
mutex_lock(&priv->conf_mutex);
+ priv->vif = NULL;
if (priv->cached_beacon)
p54_tx_cancel(dev, priv->cached_beacon);
priv->mode = NL80211_IFTYPE_MONITOR;
@@ -2344,61 +2374,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
struct p54_common *priv = dev->priv;
struct sk_buff *skb;
struct p54_keycache *rxkey;
+ int slot, ret = 0;
u8 algo = 0;
if (modparam_nohwcrypt)
return -EOPNOTSUPP;
- if (cmd == DISABLE_KEY)
- algo = 0;
- else {
+ mutex_lock(&priv->conf_mutex);
+ if (cmd == SET_KEY) {
switch (key->alg) {
case ALG_TKIP:
if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
- BR_DESC_PRIV_CAP_TKIP)))
- return -EOPNOTSUPP;
+ BR_DESC_PRIV_CAP_TKIP))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_TKIPMICHAEL;
break;
case ALG_WEP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP))
- return -EOPNOTSUPP;
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_WEP;
break;
case ALG_CCMP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP))
- return -EOPNOTSUPP;
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_AESCCMP;
break;
default:
- return -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
}
- }
+ slot = bitmap_find_free_region(priv->used_rxkeys,
+ priv->rx_keycache_size, 0);
- if (key->keyidx > priv->rx_keycache_size) {
- /*
- * The device supports the choosen algorithm, but the firmware
- * does not provide enough key slots to store all of them.
- * So, incoming frames have to be decoded by the mac80211 stack,
- * but we can still offload encryption for outgoing frames.
- */
+ if (slot < 0) {
+ /*
+ * The device supports the choosen algorithm, but the
+ * firmware does not provide enough key slots to store
+ * all of them.
+ * But encryption offload for outgoing frames is always
+ * possible, so we just pretend that the upload was
+ * successful and do the decryption in software.
+ */
- return 0;
+ /* mark the key as invalid. */
+ key->hw_key_idx = 0xff;
+ goto out_unlock;
+ }
+ } else {
+ slot = key->hw_key_idx;
+
+ if (slot == 0xff) {
+ /* This key was not uploaded into the rx key cache. */
+
+ goto out_unlock;
+ }
+
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ algo = 0;
}
- mutex_lock(&priv->conf_mutex);
skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
- P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC);
+ P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
if (!skb) {
- mutex_unlock(&priv->conf_mutex);
- return -ENOMEM;
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ ret = -ENOSPC;
+ goto out_unlock;
}
- /* TODO: some devices have 4 more free slots for rx keys */
rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
- rxkey->entry = key->keyidx;
+ rxkey->entry = slot;
rxkey->key_id = key->keyidx;
rxkey->key_type = algo;
if (sta)
@@ -2416,11 +2469,51 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
}
priv->tx(dev, skb);
+ key->hw_key_idx = slot;
+
+out_unlock:
mutex_unlock(&priv->conf_mutex);
- return 0;
+ return ret;
}
#ifdef CONFIG_P54_LEDS
+static void p54_update_leds(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ led_work.work);
+ int err, i, tmp, blink_delay = 400;
+ bool rerun = false;
+
+ /* Don't toggle the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].toggled) {
+ priv->softled_state |= BIT(i);
+
+ tmp = 70 + 200 / (priv->leds[i].toggled);
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ if (priv->leds[i].led_dev.brightness == LED_OFF)
+ rerun = true;
+
+ priv->leds[i].toggled =
+ !!priv->leds[i].led_dev.brightness;
+ } else
+ priv->softled_state &= ~BIT(i);
+
+ err = p54_set_leds(priv->hw);
+ if (err && net_ratelimit())
+ printk(KERN_ERR "%s: failed to update LEDs.\n",
+ wiphy_name(priv->hw->wiphy));
+
+ if (rerun)
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
static void p54_led_brightness_set(struct led_classdev *led_dev,
enum led_brightness brightness)
{
@@ -2428,28 +2521,23 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
led_dev);
struct ieee80211_hw *dev = led->hw_dev;
struct p54_common *priv = dev->priv;
- int err;
- /* Don't toggle the LED, when the device is down. */
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
return ;
- if (brightness != LED_OFF)
- priv->softled_state |= BIT(led->index);
- else
- priv->softled_state &= ~BIT(led->index);
-
- err = p54_set_leds(dev);
- if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update %s LED.\n",
- wiphy_name(dev->wiphy), led_dev->name);
+ if (brightness) {
+ led->toggled++;
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ HZ/10);
+ }
}
static int p54_register_led(struct ieee80211_hw *dev,
- struct p54_led_dev *led,
unsigned int led_index,
char *name, char *trigger)
{
+ struct p54_common *priv = dev->priv;
+ struct p54_led_dev *led = &priv->leds[led_index];
int err;
if (led->registered)
@@ -2482,19 +2570,30 @@ static int p54_init_leds(struct ieee80211_hw *dev)
* TODO:
* Figure out if the EEPROM contains some hints about the number
* of available/programmable LEDs of the device.
- * But for now, we can assume that we have two programmable LEDs.
*/
- err = p54_register_led(dev, &priv->assoc_led, 0, "assoc",
+ INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+ err = p54_register_led(dev, 0, "assoc",
ieee80211_get_assoc_led_name(dev));
if (err)
return err;
- err = p54_register_led(dev, &priv->tx_led, 1, "tx",
+ err = p54_register_led(dev, 1, "tx",
ieee80211_get_tx_led_name(dev));
if (err)
return err;
+ err = p54_register_led(dev, 2, "rx",
+ ieee80211_get_rx_led_name(dev));
+ if (err)
+ return err;
+
+ err = p54_register_led(dev, 3, "radio",
+ ieee80211_get_radio_led_name(dev));
+ if (err)
+ return err;
+
err = p54_set_leds(dev);
return err;
}
@@ -2502,11 +2601,11 @@ static int p54_init_leds(struct ieee80211_hw *dev)
static void p54_unregister_leds(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
+ int i;
- if (priv->tx_led.registered)
- led_classdev_unregister(&priv->tx_led.led_dev);
- if (priv->assoc_led.registered)
- led_classdev_unregister(&priv->assoc_led.led_dev);
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].registered)
+ led_classdev_unregister(&priv->leds[i].led_dev);
}
#endif /* CONFIG_P54_LEDS */
@@ -2607,21 +2706,10 @@ void p54_free_common(struct ieee80211_hw *dev)
kfree(priv->iq_autocal);
kfree(priv->output_limit);
kfree(priv->curve_data);
+ kfree(priv->used_rxkeys);
#ifdef CONFIG_P54_LEDS
p54_unregister_leds(dev);
#endif /* CONFIG_P54_LEDS */
}
EXPORT_SYMBOL_GPL(p54_free_common);
-
-static int __init p54_init(void)
-{
- return 0;
-}
-
-static void __exit p54_exit(void)
-{
-}
-
-module_init(p54_init);
-module_exit(p54_exit);
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index d1fe577de3d..59a5e778bb0 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -167,18 +167,36 @@ static const struct p54spi_spi_reg p54spi_registers_array[] =
static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
{
int i;
- __le32 buffer;
for (i = 0; i < 2000; i++) {
- p54spi_spi_read(priv, reg, &buffer, sizeof(buffer));
- if (buffer == bits)
+ __le32 buffer = p54spi_read32(priv, reg);
+ if ((buffer & bits) == bits)
return 1;
- msleep(1);
+ msleep(0);
}
return 0;
}
+static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
+ const void *buf, size_t len)
+{
+ p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
+ cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
+
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
+ cpu_to_le32(HOST_ALLOWED))) {
+ dev_err(&priv->spi->dev, "spi_write_dma not allowed "
+ "to DMA write.\n");
+ return -EAGAIN;
+ }
+
+ p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len));
+ p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base);
+ p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len);
+ return 0;
+}
+
static int p54spi_request_firmware(struct ieee80211_hw *dev)
{
struct p54s_priv *priv = dev->priv;
@@ -228,8 +246,15 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev)
static int p54spi_upload_firmware(struct ieee80211_hw *dev)
{
struct p54s_priv *priv = dev->priv;
- unsigned long fw_len, fw_addr;
- long _fw_len;
+ unsigned long fw_len, _fw_len;
+ unsigned int offset = 0;
+ int err = 0;
+ u8 *fw;
+
+ fw_len = priv->firmware->size;
+ fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
/* stop the device */
p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
@@ -244,36 +269,17 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev)
msleep(TARGET_BOOT_SLEEP);
- fw_addr = ISL38XX_DEV_FIRMWARE_ADDR;
- fw_len = priv->firmware->size;
-
while (fw_len > 0) {
_fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE);
- p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
-
- if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED)) == 0) {
- dev_err(&priv->spi->dev, "fw_upload not allowed "
- "to DMA write.");
- return -EAGAIN;
- }
-
- p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN,
- cpu_to_le16(_fw_len));
- p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE,
- cpu_to_le32(fw_addr));
-
- p54spi_spi_write(priv, SPI_ADRS_DMA_DATA,
- &priv->firmware->data, _fw_len);
+ err = p54spi_spi_write_dma(priv, cpu_to_le32(
+ ISL38XX_DEV_FIRMWARE_ADDR + offset),
+ (fw + offset), _fw_len);
+ if (err < 0)
+ goto out;
fw_len -= _fw_len;
- fw_addr += _fw_len;
-
- /* FIXME: I think this doesn't work if firmware is large,
- * this loop goes to second round. fw->data is not
- * increased at all! */
+ offset += _fw_len;
}
BUG_ON(fw_len != 0);
@@ -292,7 +298,10 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev)
p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT));
msleep(TARGET_BOOT_SLEEP);
- return 0;
+
+out:
+ kfree(fw);
+ return err;
}
static void p54spi_power_off(struct p54s_priv *priv)
@@ -320,21 +329,15 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val)
static void p54spi_wakeup(struct p54s_priv *priv)
{
- unsigned long timeout;
- u32 ints;
-
/* wake the chip */
p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
cpu_to_le32(SPI_TARGET_INT_WAKEUP));
/* And wait for the READY interrupt */
- timeout = jiffies + HZ;
-
- ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
- while (!(ints & SPI_HOST_INT_READY)) {
- if (time_after(jiffies, timeout))
- goto out;
- ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
+ if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
+ cpu_to_le32(SPI_HOST_INT_READY))) {
+ dev_err(&priv->spi->dev, "INT_READY timeout\n");
+ goto out;
}
p54spi_int_ack(priv, SPI_HOST_INT_READY);
@@ -385,7 +388,12 @@ static int p54spi_rx(struct p54s_priv *priv)
return 0;
}
- skb = dev_alloc_skb(len);
+
+ /* Firmware may insert up to 4 padding bytes after the lmac header,
+ * but it does not amend the size of SPI data transfer.
+ * Such packets has correct data size in header, thus referencing
+ * past the end of allocated skb. Reserve extra 4 bytes for this case */
+ skb = dev_alloc_skb(len + 4);
if (!skb) {
dev_err(&priv->spi->dev, "could not alloc skb");
return 0;
@@ -393,6 +401,9 @@ static int p54spi_rx(struct p54s_priv *priv)
p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
p54spi_sleep(priv);
+ /* Put additional bytes to compensate for the possible
+ * alignment-caused truncation */
+ skb_put(skb, 4);
if (p54_rx(priv->hw, skb) == 0)
dev_kfree_skb(skb);
@@ -414,39 +425,27 @@ static irqreturn_t p54spi_interrupt(int irq, void *config)
static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
{
struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54s_dma_regs dma_regs;
- unsigned long timeout;
int ret = 0;
- u32 ints;
p54spi_wakeup(priv);
- dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE);
- dma_regs.len = cpu_to_le16(skb->len);
- dma_regs.addr = hdr->req_id;
-
- p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs,
- sizeof(dma_regs));
-
- p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len);
+ ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len);
+ if (ret < 0)
+ goto out;
- timeout = jiffies + 2 * HZ;
- ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
- while (!(ints & SPI_HOST_INT_WR_READY)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&priv->spi->dev, "WR_READY timeout");
- ret = -1;
- goto out;
- }
- ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
+ if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
+ cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ dev_err(&priv->spi->dev, "WR_READY timeout\n");
+ ret = -1;
+ goto out;
}
p54spi_int_ack(priv, SPI_HOST_INT_WR_READY);
p54spi_sleep(priv);
-out:
if (FREE_AFTER_TX(skb))
p54_free_skb(priv->hw, skb);
+out:
return ret;
}
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index db91db77650..52fc647e6cb 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -42,6 +42,7 @@
#include <linux/ctype.h>
#include <linux/spinlock.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/rndis_host.h>
@@ -316,25 +317,61 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))
+static const struct ieee80211_channel rndis_channels[] = {
+ { .center_freq = 2412 },
+ { .center_freq = 2417 },
+ { .center_freq = 2422 },
+ { .center_freq = 2427 },
+ { .center_freq = 2432 },
+ { .center_freq = 2437 },
+ { .center_freq = 2442 },
+ { .center_freq = 2447 },
+ { .center_freq = 2452 },
+ { .center_freq = 2457 },
+ { .center_freq = 2462 },
+ { .center_freq = 2467 },
+ { .center_freq = 2472 },
+ { .center_freq = 2484 },
+};
+
+static const struct ieee80211_rate rndis_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60 },
+ { .bitrate = 90 },
+ { .bitrate = 120 },
+ { .bitrate = 180 },
+ { .bitrate = 240 },
+ { .bitrate = 360 },
+ { .bitrate = 480 },
+ { .bitrate = 540 }
+};
+
/* RNDIS device private data */
struct rndis_wext_private {
- char name[32];
-
struct usbnet *usbdev;
+ struct wireless_dev wdev;
+
+ struct cfg80211_scan_request *scan_request;
+
struct workqueue_struct *workqueue;
struct delayed_work stats_work;
+ struct delayed_work scan_work;
struct work_struct work;
struct mutex command_lock;
spinlock_t stats_lock;
unsigned long work_pending;
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
+ struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
+
struct iw_statistics iwstats;
struct iw_statistics privstats;
- int nick_len;
- char nick[32];
-
int caps;
int multicast_size;
@@ -368,8 +405,22 @@ struct rndis_wext_private {
u8 command_buffer[COMMAND_BUFFER_SIZE];
};
+/*
+ * cfg80211 ops
+ */
+static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
+
+static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+
+static struct cfg80211_ops rndis_config_ops = {
+ .change_virtual_intf = rndis_change_virtual_intf,
+ .scan = rndis_scan,
+};
-static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 };
+static void *rndis_wiphy_privid = &rndis_wiphy_privid;
static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
@@ -1086,131 +1137,180 @@ static void set_multicast_list(struct usbnet *usbdev)
/*
- * wireless extension handlers
+ * cfg80211 ops
*/
-
-static int rndis_iw_commit(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
{
- /* dummy op */
- return 0;
+ struct net_device *dev;
+ struct usbnet *usbdev;
+ int mode;
+
+ /* we're under RTNL */
+ dev = __dev_get_by_index(&init_net, ifindex);
+ if (!dev)
+ return -ENODEV;
+ usbdev = netdev_priv(dev);
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ mode = ndis_80211_infra_adhoc;
+ break;
+ case NL80211_IFTYPE_STATION:
+ mode = ndis_80211_infra_infra;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return set_infra_mode(usbdev, mode);
}
-static int rndis_iw_get_range(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+#define SCAN_DELAY_JIFFIES (HZ)
+static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
{
- struct iw_range *range = (struct iw_range *)extra;
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
- int len, ret, i, j, num, has_80211g_rates;
- u8 rates[8];
- __le32 tx_power;
+ int ret;
+ __le32 tmp;
- devdbg(usbdev, "SIOCGIWRANGE");
+ devdbg(usbdev, "cfg80211.scan");
- /* clear iw_range struct */
- memset(range, 0, sizeof(*range));
- wrqu->data.length = sizeof(*range);
+ if (!request)
+ return -EINVAL;
- range->txpower_capa = IW_TXPOW_MWATT;
- range->num_txpower = 1;
- if (priv->caps & CAP_SUPPORT_TXPOWER) {
- len = sizeof(tx_power);
- ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
- &tx_power, &len);
- if (ret == 0 && le32_to_cpu(tx_power) != 0xFF)
- range->txpower[0] = le32_to_cpu(tx_power);
- else
- range->txpower[0] = get_bcm4320_power(priv);
- } else
- range->txpower[0] = get_bcm4320_power(priv);
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
- len = sizeof(rates);
- ret = rndis_query_oid(usbdev, OID_802_11_SUPPORTED_RATES, &rates,
- &len);
- has_80211g_rates = 0;
+ priv->scan_request = request;
+
+ tmp = cpu_to_le32(1);
+ ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
+ sizeof(tmp));
if (ret == 0) {
- j = 0;
- for (i = 0; i < len; i++) {
- if (rates[i] == 0)
- break;
- range->bitrate[j] = (rates[i] & 0x7f) * 500000;
- /* check for non 802.11b rates */
- if (range->bitrate[j] == 6000000 ||
- range->bitrate[j] == 9000000 ||
- (range->bitrate[j] >= 12000000 &&
- range->bitrate[j] != 22000000))
- has_80211g_rates = 1;
- j++;
- }
- range->num_bitrates = j;
- } else
- range->num_bitrates = 0;
-
- /* fill in 802.11g rates */
- if (has_80211g_rates) {
- num = range->num_bitrates;
- for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) {
- for (j = 0; j < num; j++) {
- if (range->bitrate[j] ==
- rates_80211g[i] * 1000000)
- break;
- }
- if (j == num)
- range->bitrate[range->num_bitrates++] =
- rates_80211g[i] * 1000000;
- if (range->num_bitrates == IW_MAX_BITRATES)
- break;
- }
+ /* Wait before retrieving scan results from device */
+ queue_delayed_work(priv->workqueue, &priv->scan_work,
+ SCAN_DELAY_JIFFIES);
+ }
- /* estimated max real througput in bps */
- range->throughput = 54 * 1000 * 1000 / 2;
+ return ret;
+}
- /* ~35% more with afterburner */
- if (priv->param_afterburner)
- range->throughput = range->throughput / 100 * 135;
- } else {
- /* estimated max real througput in bps */
- range->throughput = 11 * 1000 * 1000 / 2;
+
+static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
+ struct ndis_80211_bssid_ex *bssid)
+{
+ struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+ struct ieee80211_channel *channel;
+ s32 signal;
+ u64 timestamp;
+ u16 capability;
+ u16 beacon_interval;
+ struct ndis_80211_fixed_ies *fixed;
+ int ie_len, bssid_len;
+ u8 *ie;
+
+ /* parse bssid structure */
+ bssid_len = le32_to_cpu(bssid->length);
+
+ if (bssid_len < sizeof(struct ndis_80211_bssid_ex) +
+ sizeof(struct ndis_80211_fixed_ies))
+ return NULL;
+
+ fixed = (struct ndis_80211_fixed_ies *)bssid->ies;
+
+ ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
+ ie_len = min(bssid_len - (int)sizeof(*bssid),
+ (int)le32_to_cpu(bssid->ie_length));
+ ie_len -= sizeof(struct ndis_80211_fixed_ies);
+ if (ie_len < 0)
+ return NULL;
+
+ /* extract data for cfg80211_inform_bss */
+ channel = ieee80211_get_channel(priv->wdev.wiphy,
+ KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config)));
+ if (!channel)
+ return NULL;
+
+ signal = level_to_qual(le32_to_cpu(bssid->rssi));
+ timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp);
+ capability = le16_to_cpu(fixed->capabilities);
+ beacon_interval = le16_to_cpu(fixed->beacon_interval);
+
+ return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
+ timestamp, capability, beacon_interval, ie, ie_len, signal,
+ GFP_KERNEL);
+}
+
+
+static int rndis_check_bssid_list(struct usbnet *usbdev)
+{
+ void *buf = NULL;
+ struct ndis_80211_bssid_list_ex *bssid_list;
+ struct ndis_80211_bssid_ex *bssid;
+ int ret = -EINVAL, len, count, bssid_len;
+
+ devdbg(usbdev, "check_bssid_list");
+
+ len = CONTROL_BUFFER_SIZE;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
}
- range->num_channels = 14;
+ ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
+ if (ret != 0)
+ goto out;
- for (i = 0; (i < 14) && (i < IW_MAX_FREQUENCIES); i++) {
- range->freq[i].i = i + 1;
- range->freq[i].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
- range->freq[i].e = 1;
+ bssid_list = buf;
+ bssid = bssid_list->bssid;
+ bssid_len = le32_to_cpu(bssid->length);
+ count = le32_to_cpu(bssid_list->num_items);
+ devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count);
+
+ while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
+ rndis_bss_info_update(usbdev, bssid);
+
+ bssid = (void *)bssid + bssid_len;
+ bssid_len = le32_to_cpu(bssid->length);
+ count--;
}
- range->num_frequency = i;
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
+out:
+ kfree(buf);
+ return ret;
+}
- range->max_qual.qual = 100;
- range->max_qual.level = 154;
- range->max_qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_INVALID;
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = WIRELESS_EXT;
+static void rndis_get_scan_results(struct work_struct *work)
+{
+ struct rndis_wext_private *priv =
+ container_of(work, struct rndis_wext_private, scan_work.work);
+ struct usbnet *usbdev = priv->usbdev;
+ int ret;
+
+ devdbg(usbdev, "get_scan_results");
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
- return 0;
+ ret = rndis_check_bssid_list(usbdev);
+
+ cfg80211_scan_done(priv->scan_request, ret < 0);
+
+ priv->scan_request = NULL;
}
-static int rndis_iw_get_name(struct net_device *dev,
+/*
+ * wireless extension handlers
+ */
+
+static int rndis_iw_commit(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
-
- strcpy(wrqu->name, priv->name);
+ /* dummy op */
return 0;
}
@@ -1422,55 +1522,6 @@ static int rndis_iw_get_auth(struct net_device *dev,
}
-static int rndis_iw_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
-
- switch (priv->infra_mode) {
- case ndis_80211_infra_adhoc:
- wrqu->mode = IW_MODE_ADHOC;
- break;
- case ndis_80211_infra_infra:
- wrqu->mode = IW_MODE_INFRA;
- break;
- /*case ndis_80211_infra_auto_unknown:*/
- default:
- wrqu->mode = IW_MODE_AUTO;
- break;
- }
- devdbg(usbdev, "SIOCGIWMODE: %08x", wrqu->mode);
- return 0;
-}
-
-
-static int rndis_iw_set_mode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- int mode;
-
- devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode);
-
- switch (wrqu->mode) {
- case IW_MODE_ADHOC:
- mode = ndis_80211_infra_adhoc;
- break;
- case IW_MODE_INFRA:
- mode = ndis_80211_infra_infra;
- break;
- /*case IW_MODE_AUTO:*/
- default:
- mode = ndis_80211_infra_auto_unknown;
- break;
- }
-
- return set_infra_mode(usbdev, mode);
-}
-
-
static int rndis_iw_set_encode(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -1619,198 +1670,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
}
-static int rndis_iw_set_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- union iwreq_data evt;
- int ret = -EINVAL;
- __le32 tmp;
-
- devdbg(usbdev, "SIOCSIWSCAN");
-
- if (wrqu->data.flags == 0) {
- tmp = cpu_to_le32(1);
- ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
- sizeof(tmp));
- evt.data.flags = 0;
- evt.data.length = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &evt, NULL);
- }
- return ret;
-}
-
-
-static char *rndis_translate_scan(struct net_device *dev,
- struct iw_request_info *info, char *cev,
- char *end_buf,
- struct ndis_80211_bssid_ex *bssid)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- u8 *ie;
- char *current_val;
- int bssid_len, ie_len, i;
- u32 beacon, atim;
- struct iw_event iwe;
- unsigned char sbuf[32];
-
- bssid_len = le32_to_cpu(bssid->length);
-
- devdbg(usbdev, "BSSID %pM", bssid->mac);
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
- cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_ADDR_LEN);
-
- devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length),
- bssid->ssid.essid);
- iwe.cmd = SIOCGIWESSID;
- iwe.u.essid.length = le32_to_cpu(bssid->ssid.length);
- iwe.u.essid.flags = 1;
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, bssid->ssid.essid);
-
- devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra));
- iwe.cmd = SIOCGIWMODE;
- switch (le32_to_cpu(bssid->net_infra)) {
- case ndis_80211_infra_adhoc:
- iwe.u.mode = IW_MODE_ADHOC;
- break;
- case ndis_80211_infra_infra:
- iwe.u.mode = IW_MODE_INFRA;
- break;
- /*case ndis_80211_infra_auto_unknown:*/
- default:
- iwe.u.mode = IW_MODE_AUTO;
- break;
- }
- cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_UINT_LEN);
-
- devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config));
- iwe.cmd = SIOCGIWFREQ;
- dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq);
- cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_FREQ_LEN);
-
- devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi));
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi));
- iwe.u.qual.level = le32_to_cpu(bssid->rssi);
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_INVALID;
- cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_QUAL_LEN);
-
- devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy));
- iwe.cmd = SIOCGIWENCODE;
- iwe.u.data.length = 0;
- if (le32_to_cpu(bssid->privacy) == ndis_80211_priv_accept_all)
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- else
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
-
- devdbg(usbdev, "RATES:");
- current_val = cev + iwe_stream_lcp_len(info);
- iwe.cmd = SIOCGIWRATE;
- for (i = 0; i < sizeof(bssid->rates); i++) {
- if (bssid->rates[i] & 0x7f) {
- iwe.u.bitrate.value =
- ((bssid->rates[i] & 0x7f) *
- 500000);
- devdbg(usbdev, " %d", iwe.u.bitrate.value);
- current_val = iwe_stream_add_value(info, cev,
- current_val, end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- }
-
- if ((current_val - cev) > iwe_stream_lcp_len(info))
- cev = current_val;
-
- beacon = le32_to_cpu(bssid->config.beacon_period);
- devdbg(usbdev, "BCN_INT %d", beacon);
- iwe.cmd = IWEVCUSTOM;
- snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
- iwe.u.data.length = strlen(sbuf);
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
-
- atim = le32_to_cpu(bssid->config.atim_window);
- devdbg(usbdev, "ATIM %d", atim);
- iwe.cmd = IWEVCUSTOM;
- snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
- iwe.u.data.length = strlen(sbuf);
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf);
-
- ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
- ie_len = min(bssid_len - (int)sizeof(*bssid),
- (int)le32_to_cpu(bssid->ie_length));
- ie_len -= sizeof(struct ndis_80211_fixed_ies);
- while (ie_len >= 2 && 2 + ie[1] <= ie_len) {
- if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 &&
- memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) ||
- ie[0] == WLAN_EID_RSN) {
- devdbg(usbdev, "IE: WPA%d",
- (ie[0] == WLAN_EID_RSN) ? 2 : 1);
- iwe.cmd = IWEVGENIE;
- /* arbitrary cut-off at 64 */
- iwe.u.data.length = min(ie[1] + 2, 64);
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie);
- }
-
- ie_len -= 2 + ie[1];
- ie += 2 + ie[1];
- }
-
- return cev;
-}
-
-
-static int rndis_iw_get_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- void *buf = NULL;
- char *cev = extra;
- struct ndis_80211_bssid_list_ex *bssid_list;
- struct ndis_80211_bssid_ex *bssid;
- int ret = -EINVAL, len, count, bssid_len;
-
- devdbg(usbdev, "SIOCGIWSCAN");
-
- len = CONTROL_BUFFER_SIZE;
- buf = kmalloc(len, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
-
- if (ret != 0)
- goto out;
-
- bssid_list = buf;
- bssid = bssid_list->bssid;
- bssid_len = le32_to_cpu(bssid->length);
- count = le32_to_cpu(bssid_list->num_items);
- devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
-
- while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
- cev = rndis_translate_scan(dev, info, cev,
- extra + IW_SCAN_MAX_DATA, bssid);
- bssid = (void *)bssid + bssid_len;
- bssid_len = le32_to_cpu(bssid->length);
- count--;
- }
-
-out:
- wrqu->data.length = cev - extra;
- wrqu->data.flags = 0;
- kfree(buf);
- return ret;
-}
-
-
static int rndis_iw_set_genie(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -1936,39 +1795,6 @@ static int rndis_iw_get_frag(struct net_device *dev,
}
-static int rndis_iw_set_nick(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
-
- devdbg(usbdev, "SIOCSIWNICK");
-
- priv->nick_len = wrqu->data.length;
- if (priv->nick_len > 32)
- priv->nick_len = 32;
-
- memcpy(priv->nick, extra, priv->nick_len);
- return 0;
-}
-
-
-static int rndis_iw_get_nick(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
-
- wrqu->data.flags = 1;
- wrqu->data.length = priv->nick_len;
- memcpy(extra, priv->nick, priv->nick_len);
-
- devdbg(usbdev, "SIOCGIWNICK: '%s'", priv->nick);
-
- return 0;
-}
-
-
static int rndis_iw_set_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -2165,20 +1991,18 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
static const iw_handler rndis_iw_handler[] =
{
IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit,
- IW_IOCTL(SIOCGIWNAME) = rndis_iw_get_name,
+ IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq,
IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq,
- IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode,
- IW_IOCTL(SIOCGIWMODE) = rndis_iw_get_mode,
- IW_IOCTL(SIOCGIWRANGE) = rndis_iw_get_range,
+ IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode,
+ IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode,
+ IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange,
IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid,
IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid,
- IW_IOCTL(SIOCSIWSCAN) = rndis_iw_set_scan,
- IW_IOCTL(SIOCGIWSCAN) = rndis_iw_get_scan,
+ IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan,
+ IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan,
IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid,
IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid,
- IW_IOCTL(SIOCSIWNICKN) = rndis_iw_set_nick,
- IW_IOCTL(SIOCGIWNICKN) = rndis_iw_get_nick,
IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate,
IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts,
IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts,
@@ -2338,12 +2162,6 @@ static int rndis_wext_get_caps(struct usbnet *usbdev)
break;
}
}
- if (priv->caps & CAP_MODE_80211A)
- strcat(priv->name, "a");
- if (priv->caps & CAP_MODE_80211B)
- strcat(priv->name, "b");
- if (priv->caps & CAP_MODE_80211G)
- strcat(priv->name, "g");
}
return retval;
@@ -2387,7 +2205,7 @@ static void rndis_update_wireless_stats(struct work_struct *work)
if (ret == 0) {
memset(&iwstats.qual, 0, sizeof(iwstats.qual));
iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi));
- iwstats.qual.level = le32_to_cpu(rssi);
+ iwstats.qual.level = level_to_qual(le32_to_cpu(rssi));
iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_INVALID;
@@ -2538,26 +2356,40 @@ static const struct net_device_ops rndis_wext_netdev_ops = {
static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
{
+ struct wiphy *wiphy;
struct rndis_wext_private *priv;
int retval, len;
__le32 tmp;
- /* allocate rndis private data */
- priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL);
- if (!priv)
+ /* allocate wiphy and rndis private data
+ * NOTE: We only support a single virtual interface, so wiphy
+ * and wireless_dev are somewhat synonymous for this device.
+ */
+ wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private));
+ if (!wiphy)
return -ENOMEM;
+ priv = wiphy_priv(wiphy);
+ usbdev->net->ieee80211_ptr = &priv->wdev;
+ priv->wdev.wiphy = wiphy;
+ priv->wdev.iftype = NL80211_IFTYPE_STATION;
+
/* These have to be initialized before calling generic_rndis_bind().
* Otherwise we'll be in big trouble in rndis_wext_early_init().
*/
usbdev->driver_priv = priv;
- strcpy(priv->name, "IEEE802.11");
usbdev->net->wireless_handlers = &rndis_iw_handlers;
priv->usbdev = usbdev;
mutex_init(&priv->command_lock);
spin_lock_init(&priv->stats_lock);
+ /* because rndis_command() sleeps we need to use workqueue */
+ priv->workqueue = create_singlethread_workqueue("rndis_wlan");
+ INIT_WORK(&priv->work, rndis_wext_worker);
+ INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
+ INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
+
/* try bind rndis_host */
retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS);
if (retval < 0)
@@ -2595,7 +2427,32 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
| IW_QUAL_QUAL_INVALID
| IW_QUAL_LEVEL_INVALID;
+ /* fill-out wiphy structure and register w/ cfg80211 */
+ memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN);
+ wiphy->privid = rndis_wiphy_privid;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC);
+ wiphy->max_scan_ssids = 1;
+
+ /* TODO: fill-out band information based on priv->caps */
rndis_wext_get_caps(usbdev);
+
+ memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
+ memcpy(priv->rates, rndis_rates, sizeof(rndis_rates));
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = ARRAY_SIZE(rndis_channels);
+ priv->band.bitrates = priv->rates;
+ priv->band.n_bitrates = ARRAY_SIZE(rndis_rates);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+
+ set_wiphy_dev(wiphy, &usbdev->udev->dev);
+
+ if (wiphy_register(wiphy)) {
+ retval = -ENODEV;
+ goto fail;
+ }
+
set_default_iw_params(usbdev);
/* turn radio on */
@@ -2603,17 +2460,19 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
disassociate(usbdev, 1);
netif_carrier_off(usbdev->net);
- /* because rndis_command() sleeps we need to use workqueue */
- priv->workqueue = create_singlethread_workqueue("rndis_wlan");
- INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
queue_delayed_work(priv->workqueue, &priv->stats_work,
round_jiffies_relative(STATS_UPDATE_JIFFIES));
- INIT_WORK(&priv->work, rndis_wext_worker);
return 0;
fail:
- kfree(priv);
+ cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_work_sync(&priv->work);
+ flush_workqueue(priv->workqueue);
+ destroy_workqueue(priv->workqueue);
+
+ wiphy_free(wiphy);
return retval;
}
@@ -2626,15 +2485,18 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf)
disassociate(usbdev, 0);
cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
destroy_workqueue(priv->workqueue);
if (priv && priv->wpa_ie_len)
kfree(priv->wpa_ie);
- kfree(priv);
rndis_unbind(usbdev, intf);
+
+ wiphy_unregister(priv->wdev.wiphy);
+ wiphy_free(priv->wdev.wiphy);
}
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 0f08773328c..411eb9cbb4e 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1361,7 +1361,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
- rt2x00_set_chip(rt2x00dev, RT2460, value, reg);
+ rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
!rt2x00_rf(&rt2x00dev->chip, RF2421)) {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 276a8232aaa..e1be67ca23d 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1525,7 +1525,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
- rt2x00_set_chip(rt2x00dev, RT2560, value, reg);
+ rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
!rt2x00_rf(&rt2x00dev->chip, RF2523) &&
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 84bd6f19acb..e03d69975ea 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -672,6 +672,12 @@ struct rt2x00_dev {
unsigned long flags;
/*
+ * Device information, Bus IRQ and name (PCI, SoC)
+ */
+ int irq;
+ const char *name;
+
+ /*
* Chipset identification.
*/
struct rt2x00_chip chip;
@@ -860,6 +866,18 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
rt2x00dev->chip.rev = rev;
}
+static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev,
+ const u16 rt)
+{
+ rt2x00dev->chip.rt = rt;
+}
+
+static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev,
+ const u16 rf, const u32 rev)
+{
+ rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev);
+}
+
static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
{
return (chipset->rt == chip);
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 7eb5cd7e5f3..eb9b981b913 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -387,7 +387,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
rt2x00link_antenna_reset(rt2x00dev);
}
-void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
+static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
{
struct link_qual *qual = &rt2x00dev->link.qual;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 9730b4f8fd2..cdd5154bd4c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -170,7 +170,6 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
{
- struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
struct data_queue *queue;
int status;
@@ -186,11 +185,11 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
/*
* Register interrupt handler.
*/
- status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
- IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
+ status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler,
+ IRQF_SHARED, rt2x00dev->name, rt2x00dev);
if (status) {
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
- pci_dev->irq, status);
+ rt2x00dev->irq, status);
goto exit;
}
@@ -270,6 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
+ u16 chip;
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
@@ -307,6 +307,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->dev = &pci_dev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
+ rt2x00dev->irq = pci_dev->irq;
+ rt2x00dev->name = pci_name(pci_dev);
+
+ /*
+ * Determine RT chipset by reading PCI header.
+ */
+ pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
+ rt2x00_set_chip_rt(rt2x00dev, chip);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 2ca8b7a9722..4346cd1494b 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2308,7 +2308,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
u32 reg;
u16 value;
u16 eeprom;
- u16 device;
/*
* Read EEPROM word for configuration.
@@ -2317,14 +2316,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Identify RF chipset.
- * To determine the RT chip we have to read the
- * PCI header of the device.
*/
- pci_read_config_word(to_pci_dev(rt2x00dev->dev),
- PCI_CONFIG_HEADER_DEVICE, &device);
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
- rt2x00_set_chip(rt2x00dev, device, value, reg);
+ rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
!rt2x00_rf(&rt2x00dev->chip, RF5325) &&
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 41e8959919f..6c71f77c816 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -63,12 +63,6 @@
*/
/*
- * PCI Configuration Header
- */
-#define PCI_CONFIG_HEADER_VENDOR 0x0000
-#define PCI_CONFIG_HEADER_DEVICE 0x0002
-
-/*
* HOST_CMD_CSR: For HOST to interrupt embedded processor
*/
#define HOST_CMD_CSR 0x0008
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
index c113b3e6904..37e3d4db0c4 100644
--- a/drivers/net/wireless/rtl818x/Makefile
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -1,5 +1,5 @@
rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
+rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o
obj-$(CONFIG_RTL8180) += rtl8180.o
obj-$(CONFIG_RTL8187) += rtl8187.o
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 9718f61809c..622196dc078 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -16,6 +16,7 @@
#define RTL8187_H
#include "rtl818x.h"
+#include "rtl8187_leds.h"
#define RTL8187_EEPROM_TXPWR_BASE 0x05
#define RTL8187_EEPROM_MAC_ADDR 0x07
@@ -102,6 +103,12 @@ struct rtl8187_priv {
struct usb_anchor anchored;
struct delayed_work work;
struct ieee80211_hw *dev;
+#ifdef CONFIG_RTL8187_LEDS
+ struct rtl8187_led led_tx;
+ struct rtl8187_led led_rx;
+ struct delayed_work led_on;
+ struct delayed_work led_off;
+#endif
u16 txpwr_base;
u8 asic_rev;
u8 is_rtl8187b;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index fd81884b9c7..ac558da92aa 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -29,6 +29,9 @@
#include "rtl8187.h"
#include "rtl8187_rtl8225.h"
+#ifdef CONFIG_RTL8187_LEDS
+#include "rtl8187_leds.h"
+#endif
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -734,10 +737,10 @@ static const u8 rtl8187b_reg_table[][3] = {
{0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0},
{0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0},
{0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0},
- {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0},
+ {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2},
- {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0},
- {0x8E, 0x08, 0}, {0x8F, 0x00, 0}
+ {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0},
+ {0x8F, 0x00, 0}
};
static int rtl8187b_init_hw(struct ieee80211_hw *dev)
@@ -1470,9 +1473,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
(*channel++).hw_value = txpwr >> 8;
}
- if (priv->is_rtl8187b)
- printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
-
/*
* XXX: Once this driver supports anything that requires
* beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
@@ -1504,6 +1504,12 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
chip_name, priv->asic_rev, priv->rf->name);
+#ifdef CONFIG_RTL8187_LEDS
+ eeprom_93cx6_read(&eeprom, 0x3F, &reg);
+ reg &= 0xFF;
+ rtl8187_leds_init(dev, reg);
+#endif
+
return 0;
err_free_dev:
@@ -1521,6 +1527,9 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
if (!dev)
return;
+#ifdef CONFIG_RTL8187_LEDS
+ rtl8187_leds_exit(dev);
+#endif
ieee80211_unregister_hw(dev);
priv = dev->priv;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
new file mode 100644
index 00000000000..b4425359224
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -0,0 +1,218 @@
+/*
+ * Linux LED driver for RTL8187
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Based on the LED handling in the r8187 driver, which is:
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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.
+ */
+
+#ifdef CONFIG_RTL8187_LEDS
+
+#include <net/mac80211.h>
+#include <linux/usb.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rtl8187.h"
+#include "rtl8187_leds.h"
+
+static void led_turn_on(struct work_struct *work)
+{
+ /* As this routine does read/write operations on the hardware, it must
+ * be run from a work queue.
+ */
+ u8 reg;
+ struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
+ led_on.work);
+ struct rtl8187_led *led = &priv->led_tx;
+
+ /* Don't change the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ /* Skip if the LED is not registered. */
+ if (!led->dev)
+ return;
+ mutex_lock(&priv->conf_mutex);
+ switch (led->ledpin) {
+ case LED_PIN_GPIO0:
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+ rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
+ break;
+ case LED_PIN_LED0:
+ reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4);
+ rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
+ break;
+ case LED_PIN_LED1:
+ reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5);
+ rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
+ break;
+ case LED_PIN_HW:
+ default:
+ break;
+ }
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static void led_turn_off(struct work_struct *work)
+{
+ /* As this routine does read/write operations on the hardware, it must
+ * be run from a work queue.
+ */
+ u8 reg;
+ struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
+ led_off.work);
+ struct rtl8187_led *led = &priv->led_tx;
+
+ /* Don't change the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ /* Skip if the LED is not registered. */
+ if (!led->dev)
+ return;
+ mutex_lock(&priv->conf_mutex);
+ switch (led->ledpin) {
+ case LED_PIN_GPIO0:
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+ rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
+ break;
+ case LED_PIN_LED0:
+ reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4);
+ rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
+ break;
+ case LED_PIN_LED1:
+ reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5);
+ rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
+ break;
+ case LED_PIN_HW:
+ default:
+ break;
+ }
+ mutex_unlock(&priv->conf_mutex);
+}
+
+/* Callback from the LED subsystem. */
+static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led,
+ led_dev);
+ struct ieee80211_hw *hw = led->dev;
+ struct rtl8187_priv *priv = hw->priv;
+
+ if (brightness == LED_OFF) {
+ queue_delayed_work(hw->workqueue, &priv->led_off, 0);
+ /* The LED is off for 1/20 sec so that it just blinks. */
+ queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20);
+ } else
+ queue_delayed_work(hw->workqueue, &priv->led_on, 0);
+}
+
+static int rtl8187_register_led(struct ieee80211_hw *dev,
+ struct rtl8187_led *led, const char *name,
+ const char *default_trigger, u8 ledpin)
+{
+ int err;
+ struct rtl8187_priv *priv = dev->priv;
+
+ if (led->dev)
+ return -EEXIST;
+ if (!default_trigger)
+ return -EINVAL;
+ led->dev = dev;
+ led->ledpin = ledpin;
+ strncpy(led->name, name, sizeof(led->name));
+
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = default_trigger;
+ led->led_dev.brightness_set = rtl8187_led_brightness_set;
+
+ err = led_classdev_register(&priv->udev->dev, &led->led_dev);
+ if (err) {
+ printk(KERN_INFO "LEDs: Failed to register %s\n", name);
+ led->dev = NULL;
+ return err;
+ }
+ return 0;
+}
+
+static void rtl8187_unregister_led(struct rtl8187_led *led)
+{
+ led_classdev_unregister(&led->led_dev);
+ led->dev = NULL;
+}
+
+void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ char name[RTL8187_LED_MAX_NAME_LEN + 1];
+ u8 ledpin;
+ int err;
+
+ /* According to the vendor driver, the LED operation depends on the
+ * customer ID encoded in the EEPROM
+ */
+ printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
+ switch (custid) {
+ case EEPROM_CID_RSVD0:
+ case EEPROM_CID_RSVD1:
+ case EEPROM_CID_SERCOMM_PS:
+ case EEPROM_CID_QMI:
+ case EEPROM_CID_DELL:
+ case EEPROM_CID_TOSHIBA:
+ ledpin = LED_PIN_GPIO0;
+ break;
+ case EEPROM_CID_ALPHA0:
+ ledpin = LED_PIN_LED0;
+ break;
+ case EEPROM_CID_HW:
+ ledpin = LED_PIN_HW;
+ break;
+ default:
+ ledpin = LED_PIN_GPIO0;
+ }
+
+ INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
+ INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
+
+ snprintf(name, sizeof(name),
+ "rtl8187-%s::tx", wiphy_name(dev->wiphy));
+ err = rtl8187_register_led(dev, &priv->led_tx, name,
+ ieee80211_get_tx_led_name(dev), ledpin);
+ if (err)
+ goto error;
+ snprintf(name, sizeof(name),
+ "rtl8187-%s::rx", wiphy_name(dev->wiphy));
+ err = rtl8187_register_led(dev, &priv->led_rx, name,
+ ieee80211_get_rx_led_name(dev), ledpin);
+ if (!err) {
+ queue_delayed_work(dev->workqueue, &priv->led_on, 0);
+ return;
+ }
+ /* registration of RX LED failed - unregister TX */
+ rtl8187_unregister_led(&priv->led_tx);
+error:
+ /* If registration of either failed, cancel delayed work */
+ cancel_delayed_work_sync(&priv->led_off);
+ cancel_delayed_work_sync(&priv->led_on);
+}
+
+void rtl8187_leds_exit(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ rtl8187_unregister_led(&priv->led_tx);
+ /* turn the LED off before exiting */
+ queue_delayed_work(dev->workqueue, &priv->led_off, 0);
+ cancel_delayed_work_sync(&priv->led_off);
+ rtl8187_unregister_led(&priv->led_rx);
+}
+#endif /* def CONFIG_RTL8187_LED */
+
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h
new file mode 100644
index 00000000000..a0332027aea
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h
@@ -0,0 +1,57 @@
+/*
+ * Definitions for RTL8187 leds
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Based on the LED handling in the r8187 driver, which is:
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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 RTL8187_LED_H
+#define RTL8187_LED_H
+
+#ifdef CONFIG_RTL8187_LEDS
+
+#define RTL8187_LED_MAX_NAME_LEN 21
+
+#include <linux/leds.h>
+#include <linux/types.h>
+
+enum {
+ LED_PIN_LED0,
+ LED_PIN_LED1,
+ LED_PIN_GPIO0,
+ LED_PIN_HW
+};
+
+enum {
+ EEPROM_CID_RSVD0 = 0x00,
+ EEPROM_CID_RSVD1 = 0xFF,
+ EEPROM_CID_ALPHA0 = 0x01,
+ EEPROM_CID_SERCOMM_PS = 0x02,
+ EEPROM_CID_HW = 0x03,
+ EEPROM_CID_TOSHIBA = 0x04,
+ EEPROM_CID_QMI = 0x07,
+ EEPROM_CID_DELL = 0x08
+};
+
+struct rtl8187_led {
+ struct ieee80211_hw *dev;
+ /* The LED class device */
+ struct led_classdev led_dev;
+ /* The pin/method used to control the led */
+ u8 ledpin;
+ /* The unique name string for this LED device. */
+ char name[RTL8187_LED_MAX_NAME_LEN + 1];
+};
+
+void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code);
+void rtl8187_leds_exit(struct ieee80211_hw *dev);
+
+#endif /* def CONFIG_RTL8187_LED */
+
+#endif /* RTL8187_LED_H */
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 0f6e43bf4fc..62d02b3c998 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1005,7 +1005,6 @@ enum rfkill_type type, char *name, u32 cap)
*data = cap;
rfkill_dev->data = data;
rfkill_dev->toggle_radio = acer_rfkill_set;
- rfkill_dev->user_claim_unsupported = 1;
err = rfkill_register(rfkill_dev);
if (err) {
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 50d9019de2b..fe171fad12c 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -434,7 +434,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wifi_rfkill->name = "hp-wifi";
wifi_rfkill->state = hp_wmi_wifi_state();
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
- wifi_rfkill->user_claim_unsupported = 1;
err = rfkill_register(wifi_rfkill);
if (err)
goto add_sysfs_error;
@@ -446,7 +445,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
bluetooth_rfkill->name = "hp-bluetooth";
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
- bluetooth_rfkill->user_claim_unsupported = 1;
err = rfkill_register(bluetooth_rfkill);
if (err)
goto register_bluetooth_error;
@@ -457,7 +455,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wwan_rfkill->name = "hp-wwan";
wwan_rfkill->state = hp_wmi_wwan_state();
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
- wwan_rfkill->user_claim_unsupported = 1;
err = rfkill_register(wwan_rfkill);
if (err)
goto register_wwan_err;
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index d3c92d777bd..184e99e7268 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1097,7 +1097,6 @@ static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
sony_wifi_rfkill->name = "sony-wifi";
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
- sony_wifi_rfkill->user_claim_unsupported = 1;
sony_wifi_rfkill->data = (void *)SONY_WIFI;
err = rfkill_register(sony_wifi_rfkill);
if (err)
@@ -1119,7 +1118,6 @@ static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
sony_bluetooth_rfkill->name = "sony-bluetooth";
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
- sony_bluetooth_rfkill->user_claim_unsupported = 1;
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
err = rfkill_register(sony_bluetooth_rfkill);
if (err)
@@ -1140,7 +1138,6 @@ static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
sony_wwan_rfkill->name = "sony-wwan";
sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
- sony_wwan_rfkill->user_claim_unsupported = 1;
sony_wwan_rfkill->data = (void *)SONY_WWAN;
err = rfkill_register(sony_wwan_rfkill);
if (err)
@@ -1161,7 +1158,6 @@ static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
sony_wimax_rfkill->name = "sony-wimax";
sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
- sony_wimax_rfkill->user_claim_unsupported = 1;
sony_wimax_rfkill->data = (void *)SONY_WIMAX;
err = rfkill_register(sony_wimax_rfkill);
if (err)
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 9f187265db8..4345089f517 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -803,7 +803,6 @@ static int __init toshiba_acpi_init(void)
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
- toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
toshiba_acpi.rfk_dev->data = &toshiba_acpi;
if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4b501b48ce8..c52e7fba4e4 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -540,7 +540,7 @@ struct ieee80211_tim_ie {
u8 dtim_period;
u8 bitmap_ctrl;
/* variable size: 1 - 251 bytes */
- u8 virtual_map[0];
+ u8 virtual_map[1];
} __attribute__ ((packed));
#define WLAN_SA_QUERY_TR_ID_LEN 16
@@ -1383,4 +1383,43 @@ static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
return -1;
}
+/**
+ * ieee80211_tu_to_usec - convert time units (TU) to microseconds
+ * @tu: the TUs
+ */
+static inline unsigned long ieee80211_tu_to_usec(unsigned long tu)
+{
+ return 1024 * tu;
+}
+
+/**
+ * ieee80211_check_tim - check if AID bit is set in TIM
+ * @tim: the TIM IE
+ * @tim_len: length of the TIM IE
+ * @aid: the AID to look for
+ */
+static inline bool ieee80211_check_tim(struct ieee80211_tim_ie *tim,
+ u8 tim_len, u16 aid)
+{
+ u8 mask;
+ u8 index, indexn1, indexn2;
+
+ if (unlikely(!tim || tim_len < sizeof(*tim)))
+ return false;
+
+ aid &= 0x3fff;
+ index = aid / 8;
+ mask = 1 << (aid & 7);
+
+ indexn1 = tim->bitmap_ctrl & 0xfe;
+ indexn2 = tim_len + indexn1 - 4;
+
+ if (index < indexn1 || index > indexn2)
+ return false;
+
+ index -= indexn1;
+
+ return !!(tim->virtual_map[index] & mask);
+}
+
#endif /* LINUX_IEEE80211_H */
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index ea1bf5ba092..c7211ab6dd4 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -25,5 +25,7 @@
#define SDIO_VENDOR_ID_MARVELL 0x02df
#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
+#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104
+#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105
#endif
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index cbe8ce3bf48..e9fd13aa79f 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -7,7 +7,7 @@
* Copyright 2008 Michael Wu <flamingice@sourmilk.net>
* Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
* Copyright 2008 Michael Buesch <mb@bu3sch.de>
- * Copyright 2008 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
*
@@ -46,8 +46,10 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
- * %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -166,6 +168,22 @@
* set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
* %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
* to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
*
* @NL80211_CMD_AUTHENTICATE: authentication request and notification.
* This command is used both as a command (request to authenticate) and
@@ -185,8 +203,12 @@
* frame, i.e., it was for the local STA and was received in correct
* state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
* MLME SAP interface (kernel providing MLME, userspace SME). The
- * included NL80211_ATTR_FRAME attribute contains the management frame
- * (including both the header and frame body, but not FCS).
+ * included %NL80211_ATTR_FRAME attribute contains the management frame
+ * (including both the header and frame body, but not FCS). This event is
+ * also used to indicate if the authentication attempt timed out. In that
+ * case the %NL80211_ATTR_FRAME attribute is replaced with a
+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ * pending authentication timed out).
* @NL80211_CMD_ASSOCIATE: association request and notification; like
* NL80211_CMD_AUTHENTICATE but for Association and Reassociation
* (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
@@ -199,6 +221,25 @@
* NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
* MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
*
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ * FREQ attribute (for the initial frequency if no peer can be found)
+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ * should be fixed rather than automatically determined. Can only be
+ * executed on a network interface that is UP, and fixed BSSID/FREQ
+ * may be rejected. Another optional parameter is the beacon interval,
+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ * given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ * determined by the network interface.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -260,6 +301,13 @@ enum nl80211_commands {
NL80211_CMD_DEAUTHENTICATE,
NL80211_CMD_DISASSOCIATE,
+ NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+ NL80211_CMD_REG_BEACON_HINT,
+
+ NL80211_CMD_JOIN_IBSS,
+ NL80211_CMD_LEAVE_IBSS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -278,6 +326,7 @@ enum nl80211_commands {
#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
/**
* enum nl80211_attrs - nl80211 netlink attributes
@@ -296,6 +345,18 @@ enum nl80211_commands {
* NL80211_CHAN_HT20 = HT20 only
* NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
* NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ * less than or equal to the RTS threshold; allowed range: 1..255;
+ * dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ * greater than the RTS threshold; allowed range: 1..255;
+ * dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ * length in octets for frames; allowed range: 256..8000, disable
+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ * larger than or equal to this use RTS/CTS handshake); allowed range:
+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
*
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name
@@ -380,6 +441,8 @@ enum nl80211_commands {
*
* @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
* a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ * that can be added to a scan request
*
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -408,6 +471,29 @@ enum nl80211_commands {
* @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
* %NL80211_CMD_DISASSOCIATE, u16
*
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ * a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ * cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ * for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -492,6 +578,24 @@ enum nl80211_attrs {
NL80211_ATTR_AUTH_TYPE,
NL80211_ATTR_REASON_CODE,
+ NL80211_ATTR_KEY_TYPE,
+
+ NL80211_ATTR_MAX_SCAN_IE_LEN,
+ NL80211_ATTR_CIPHER_SUITES,
+
+ NL80211_ATTR_FREQ_BEFORE,
+ NL80211_ATTR_FREQ_AFTER,
+
+ NL80211_ATTR_FREQ_FIXED,
+
+
+ NL80211_ATTR_WIPHY_RETRY_SHORT,
+ NL80211_ATTR_WIPHY_RETRY_LONG,
+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+ NL80211_ATTR_TIMED_OUT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1062,4 +1166,17 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ */
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+ NL80211_KEYTYPE_PEERKEY,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ee98cd57088..ea061e290d0 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2313,6 +2313,8 @@
#define PCI_VENDOR_ID_QMI 0x1a32
+#define PCI_VENDOR_ID_AZWAVE 0x1a3b
+
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 164332cbb77..de18ef227e0 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -52,23 +52,12 @@ enum rfkill_state {
RFKILL_STATE_MAX, /* marker for last valid state */
};
-/*
- * These are DEPRECATED, drivers using them should be verified to
- * comply with the rfkill usage guidelines in Documentation/rfkill.txt
- * and then converted to use the new names for rfkill_state
- */
-#define RFKILL_STATE_OFF RFKILL_STATE_SOFT_BLOCKED
-#define RFKILL_STATE_ON RFKILL_STATE_UNBLOCKED
-
/**
* struct rfkill - rfkill control structure.
* @name: Name of the switch.
* @type: Radio type which the button controls, the value stored
* here should be a value from enum rfkill_type.
* @state: State of the switch, "UNBLOCKED" means radio can operate.
- * @user_claim_unsupported: Whether the hardware supports exclusive
- * RF-kill control by userspace. Set this before registering.
- * @user_claim: Set when the switch is controlled exlusively by userspace.
* @mutex: Guards switch state transitions. It serializes callbacks
* and also protects the state.
* @data: Pointer to the RF button drivers private data which will be
@@ -91,9 +80,6 @@ struct rfkill {
const char *name;
enum rfkill_type type;
- bool user_claim_unsupported;
- bool user_claim;
-
/* the mutex serializes callbacks and also protects
* the state */
struct mutex mutex;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5389afdc129..b8a76764e1c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1,71 +1,217 @@
#ifndef __NET_CFG80211_H
#define __NET_CFG80211_H
+/*
+ * 802.11 device and configuration interface
+ *
+ * Copyright 2006-2009 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.
+ */
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/nl80211.h>
#include <linux/if_ether.h>
#include <linux/ieee80211.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/genetlink.h>
+#include <net/regulatory.h>
+
/* remove once we remove the wext stuff */
#include <net/iw_handler.h>
+#include <linux/wireless.h>
+
/*
- * 802.11 configuration in-kernel interface
+ * wireless hardware capability structures
+ */
+
+/**
+ * enum ieee80211_band - supported frequency bands
+ *
+ * The bands are assigned this way because the supported
+ * bitrates differ in these bands.
*
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * @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
+};
/**
- * struct vif_params - describes virtual interface parameters
- * @mesh_id: mesh ID to use
- * @mesh_id_len: length of the mesh ID
+ * 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.
+ * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
+ * is not permitted.
+ * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
+ * is not permitted.
*/
-struct vif_params {
- u8 *mesh_id;
- int mesh_id_len;
+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,
+ IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4,
+ IEEE80211_CHAN_NO_FAT_BELOW = 1<<5,
};
-/* Radiotap header iteration
- * implemented in net/wireless/radiotap.c
- * docs in Documentation/networking/radiotap-headers.txt
+/**
+ * struct ieee80211_channel - channel definition
+ *
+ * This structure describes a single channel for use
+ * with cfg80211.
+ *
+ * @center_freq: center frequency in MHz
+ * @max_bandwidth: maximum allowed bandwidth for this channel, 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)
+ * @beacon_found: helper to regulatory code to indicate when a beacon
+ * has been found on this channel. Use regulatory_hint_found_beacon()
+ * to enable this, this is is useful only on 5 GHz band.
+ * @orig_mag: internal use
+ * @orig_mpwr: internal use
*/
+struct ieee80211_channel {
+ enum ieee80211_band band;
+ u16 center_freq;
+ u8 max_bandwidth;
+ u16 hw_value;
+ u32 flags;
+ int max_antenna_gain;
+ int max_power;
+ bool beacon_found;
+ u32 orig_flags;
+ int orig_mag, orig_mpwr;
+};
+
/**
- * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
- * @rtheader: pointer to the radiotap header we are walking through
- * @max_length: length of radiotap header in cpu byte ordering
- * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
- * @this_arg: pointer to current radiotap arg
- * @arg_index: internal next argument index
- * @arg: internal next argument pointer
- * @next_bitmap: internal pointer to next present u32
- * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ * 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_radiotap_iterator {
- struct ieee80211_radiotap_header *rtheader;
- int max_length;
- int this_arg_index;
- u8 *this_arg;
+/**
+ * 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;
+};
- int arg_index;
- u8 *arg;
- __le32 *next_bitmap;
- u32 bitmap_shifter;
+/**
+ * struct ieee80211_sta_ht_cap - 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 the STA
+ * @cap: HT capabilities map as described in 802.11n spec
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
+ * @mcs: Supported MCS rates
+ */
+struct ieee80211_sta_ht_cap {
+ u16 cap; /* use IEEE80211_HT_CAP_ */
+ bool ht_supported;
+ u8 ampdu_factor;
+ u8 ampdu_density;
+ struct ieee80211_mcs_info mcs;
};
-extern int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length);
+/**
+ * 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_sta_ht_cap ht_cap;
+};
-extern int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator);
+/*
+ * Wireless hardware/device configuration structures and methods
+ */
+/**
+ * struct vif_params - describes virtual interface parameters
+ * @mesh_id: mesh ID to use
+ * @mesh_id_len: length of the mesh ID
+ */
+struct vif_params {
+ u8 *mesh_id;
+ int mesh_id_len;
+};
- /**
+/**
* struct key_params - key information
*
* Information about a key
@@ -348,92 +494,6 @@ struct bss_parameters {
u8 basic_rates_len;
};
-/**
- * enum environment_cap - Environment parsed from country IE
- * @ENVIRON_ANY: indicates country IE applies to both indoor and
- * outdoor operation.
- * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation
- * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation
- */
-enum environment_cap {
- ENVIRON_ANY,
- ENVIRON_INDOOR,
- ENVIRON_OUTDOOR,
-};
-
-/**
- * struct regulatory_request - used to keep track of regulatory requests
- *
- * @wiphy_idx: this is set if this request's initiator is
- * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
- * can be used by the wireless core to deal with conflicts
- * and potentially inform users of which devices specifically
- * cased the conflicts.
- * @initiator: indicates who sent this request, could be any of
- * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
- * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
- * regulatory domain. We have a few special codes:
- * 00 - World regulatory domain
- * 99 - built by driver but a specific alpha2 cannot be determined
- * 98 - result of an intersection between two regulatory domains
- * @intersect: indicates whether the wireless core should intersect
- * the requested regulatory domain with the presently set regulatory
- * domain.
- * @country_ie_checksum: checksum of the last processed and accepted
- * country IE
- * @country_ie_env: lets us know if the AP is telling us we are outdoor,
- * indoor, or if it doesn't matter
- * @list: used to insert into the reg_requests_list linked list
- */
-struct regulatory_request {
- int wiphy_idx;
- enum nl80211_reg_initiator initiator;
- char alpha2[2];
- bool intersect;
- u32 country_ie_checksum;
- enum environment_cap country_ie_env;
- struct list_head list;
-};
-
-struct ieee80211_freq_range {
- u32 start_freq_khz;
- u32 end_freq_khz;
- u32 max_bandwidth_khz;
-};
-
-struct ieee80211_power_rule {
- u32 max_antenna_gain;
- u32 max_eirp;
-};
-
-struct ieee80211_reg_rule {
- struct ieee80211_freq_range freq_range;
- struct ieee80211_power_rule power_rule;
- u32 flags;
-};
-
-struct ieee80211_regdomain {
- u32 n_reg_rules;
- char alpha2[2];
- struct ieee80211_reg_rule reg_rules[];
-};
-
-#define MHZ_TO_KHZ(freq) ((freq) * 1000)
-#define KHZ_TO_MHZ(freq) ((freq) / 1000)
-#define DBI_TO_MBI(gain) ((gain) * 100)
-#define MBI_TO_DBI(gain) ((gain) / 100)
-#define DBM_TO_MBM(gain) ((gain) * 100)
-#define MBM_TO_DBM(gain) ((gain) / 100)
-
-#define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \
- .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
- .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
- .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
- .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \
- .power_rule.max_eirp = DBM_TO_MBM(eirp), \
- .flags = reg_flags, \
- }
-
struct mesh_config {
/* Timeouts in ms */
/* Mesh plink management parameters */
@@ -504,7 +564,7 @@ struct cfg80211_scan_request {
int n_ssids;
struct ieee80211_channel **channels;
u32 n_channels;
- u8 *ie;
+ const u8 *ie;
size_t ie_len;
/* internal */
@@ -659,6 +719,47 @@ struct cfg80211_disassoc_request {
};
/**
+ * struct cfg80211_ibss_params - IBSS parameters
+ *
+ * This structure defines the IBSS parameters for the join_ibss()
+ * method.
+ *
+ * @ssid: The SSID, will always be non-null.
+ * @ssid_len: The length of the SSID, will always be non-zero.
+ * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not
+ * search for IBSSs with a different BSSID.
+ * @channel: The channel to use if no IBSS can be found to join.
+ * @channel_fixed: The channel should be fixed -- do not search for
+ * IBSSs to join on other channels.
+ * @ie: information element(s) to include in the beacon
+ * @ie_len: length of that
+ * @beacon_interval: beacon interval to use
+ */
+struct cfg80211_ibss_params {
+ u8 *ssid;
+ u8 *bssid;
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u8 ssid_len, ie_len;
+ u16 beacon_interval;
+ bool channel_fixed;
+};
+
+/**
+ * enum wiphy_params_flags - set_wiphy_params bitfield values
+ * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
+ * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
+ * WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
+ * WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
+ */
+enum wiphy_params_flags {
+ WIPHY_PARAM_RETRY_SHORT = 1 << 0,
+ WIPHY_PARAM_RETRY_LONG = 1 << 1,
+ WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2,
+ WIPHY_PARAM_RTS_THRESHOLD = 1 << 3,
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -733,6 +834,16 @@ struct cfg80211_disassoc_request {
* @assoc: Request to (re)associate with the specified peer
* @deauth: Request to deauthenticate from the specified peer
* @disassoc: Request to disassociate from the specified peer
+ *
+ * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
+ * cfg80211_ibss_joined(), also call that function when changing BSSID due
+ * to a merge.
+ * @leave_ibss: Leave the IBSS.
+ *
+ * @set_wiphy_params: Notify that wiphy parameters have changed;
+ * @changed bitfield (see &enum wiphy_params_flags) describes which values
+ * have changed. The actual parameter values are available in
+ * struct wiphy. If returning an error, no value should be changed.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@@ -818,9 +929,414 @@ struct cfg80211_ops {
struct cfg80211_deauth_request *req);
int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_disassoc_request *req);
+
+ int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+ int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
+
+ int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
+};
+
+/*
+ * wireless hardware and networking interfaces structures
+ * and registration/helper functions
+ */
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @custom_regulatory: tells us the driver for this device
+ * has its own custom regulatory domain and cannot identify the
+ * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * we will disregard the first regulatory hint (when the
+ * initiator is %REGDOM_SET_BY_CORE).
+ * @strict_regulatory: tells us the driver for this device will ignore
+ * regulatory domain settings until it gets its own regulatory domain
+ * via its regulatory_hint(). After its gets its own regulatory domain
+ * it will only allow further regulatory domain settings to further
+ * enhance compliance. For example if channel 13 and 14 are disabled
+ * by this regulatory domain no user regulatory domain can enable these
+ * channels at a later time. This can be used for devices which do not
+ * have calibration information gauranteed for frequencies or settings
+ * outside of its regulatory domain.
+ * @reg_notifier: the driver's regulatory notification callback
+ * @regd: the driver's regulatory domain, if one was requested via
+ * the regulatory_hint() API. This can be used by the driver
+ * on the reg_notifier() if it chooses to ignore future
+ * regulatory domain changes caused by other drivers.
+ * @signal_type: signal type reported in &struct cfg80211_bss.
+ * @cipher_suites: supported cipher suites
+ * @n_cipher_suites: number of supported cipher suites
+ * @retry_short: Retry limit for short frames (dot11ShortRetryLimit)
+ * @retry_long: Retry limit for long frames (dot11LongRetryLimit)
+ * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
+ * -1 = fragmentation disabled, only odd values >= 256 used
+ * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
+ */
+struct wiphy {
+ /* assign these fields before you register the wiphy */
+
+ /* permanent MAC address */
+ u8 perm_addr[ETH_ALEN];
+
+ /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
+ u16 interface_modes;
+
+ bool custom_regulatory;
+ bool strict_regulatory;
+
+ enum cfg80211_signal_type signal_type;
+
+ int bss_priv_size;
+ u8 max_scan_ssids;
+ u16 max_scan_ie_len;
+
+ int n_cipher_suites;
+ const u32 *cipher_suites;
+
+ u8 retry_short;
+ u8 retry_long;
+ u32 frag_threshold;
+ u32 rts_threshold;
+
+ /* 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];
+
+ /* Lets us get back the wiphy on the callback */
+ int (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request);
+
+ /* fields below are read-only, assigned by cfg80211 */
+
+ const struct ieee80211_regdomain *regd;
+
+ /* 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)));
+};
+
+/**
+ * wiphy_priv - return priv from wiphy
+ *
+ * @wiphy: the wiphy whose priv pointer to return
+ */
+static inline void *wiphy_priv(struct wiphy *wiphy)
+{
+ BUG_ON(!wiphy);
+ return &wiphy->priv;
+}
+
+/**
+ * set_wiphy_dev - set device pointer for wiphy
+ *
+ * @wiphy: The wiphy whose device to bind
+ * @dev: The device to parent it to
+ */
+static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
+{
+ wiphy->dev.parent = dev;
+}
+
+/**
+ * wiphy_dev - get wiphy dev pointer
+ *
+ * @wiphy: The wiphy whose device struct to look up
+ */
+static inline struct device *wiphy_dev(struct wiphy *wiphy)
+{
+ return wiphy->dev.parent;
+}
+
+/**
+ * wiphy_name - get wiphy name
+ *
+ * @wiphy: The wiphy whose name to return
+ */
+static inline const char *wiphy_name(struct wiphy *wiphy)
+{
+ return dev_name(&wiphy->dev);
+}
+
+/**
+ * wiphy_new - create a new wiphy for use with cfg80211
+ *
+ * @ops: The configuration operations for this device
+ * @sizeof_priv: The size of the private area to allocate
+ *
+ * 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
+ *
+ * @wiphy: The wiphy to register.
+ *
+ * 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
+ *
+ * @wiphy: The wiphy to unregister.
+ *
+ * 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
+ *
+ * @wiphy: The wiphy to free
+ */
+extern void wiphy_free(struct wiphy *wiphy);
+
+/**
+ * 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
+ * @iftype: interface type
+ * @list: (private) Used to collect the interfaces
+ * @netdev: (private) Used to reference back to the netdev
+ * @current_bss: (private) Used by the internal configuration code
+ * @bssid: (private) Used by the internal configuration code
+ * @ssid: (private) Used by the internal configuration code
+ * @ssid_len: (private) Used by the internal configuration code
+ * @wext: (private) Used by the internal wireless extensions compat code
+ * @wext_bssid: (private) Used by the internal wireless extensions compat code
+ */
+struct wireless_dev {
+ struct wiphy *wiphy;
+ enum nl80211_iftype iftype;
+
+ /* private to the generic wireless code */
+ struct list_head list;
+ struct net_device *netdev;
+
+ /* currently used for IBSS - might be rearranged in the future */
+ struct cfg80211_bss *current_bss;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len;
+
+#ifdef CONFIG_WIRELESS_EXT
+ /* wext data */
+ struct cfg80211_ibss_params wext;
+ u8 wext_bssid[ETH_ALEN];
+#endif
+};
+
+/**
+ * wdev_priv - return wiphy priv from wireless_dev
+ *
+ * @wdev: The wireless device whose wiphy's priv pointer to return
+ */
+static inline void *wdev_priv(struct wireless_dev *wdev)
+{
+ BUG_ON(!wdev);
+ return wiphy_priv(wdev->wiphy);
+}
+
+/*
+ * Utility functions
+ */
+
+/**
+ * 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);
+
+/*
+ * Name indirection necessary because the ieee80211 code also has
+ * a function named "ieee80211_get_channel", so if you include
+ * cfg80211's header file you get cfg80211's version, if you try
+ * to include both header files you'll (rightfully!) get a symbol
+ * clash.
+ */
+extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
+ int freq);
+/**
+ * ieee80211_get_channel - get channel struct from wiphy for specified frequency
+ */
+static inline struct ieee80211_channel *
+ieee80211_get_channel(struct wiphy *wiphy, int freq)
+{
+ return __ieee80211_get_channel(wiphy, freq);
+}
+
+/**
+ * ieee80211_get_response_rate - get basic rate for a given rate
+ *
+ * @sband: the band to look for rates in
+ * @basic_rates: bitmap of basic rates
+ * @bitrate: the bitrate for which to find the basic rate
+ *
+ * This function returns the basic rate corresponding to a given
+ * bitrate, that is the next lower bitrate contained in the basic
+ * rate map, which is, for this function, given as a bitmap of
+ * indices of rates in the band's bitrate table.
+ */
+struct ieee80211_rate *
+ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
+ u32 basic_rates, int bitrate);
+
+/*
+ * Radiotap parsing functions -- for controlled injection support
+ *
+ * Implemented in net/wireless/radiotap.c
+ * Documentation in Documentation/networking/radiotap-headers.txt
+ */
+
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ u8 *this_arg;
+
+ int arg_index;
+ u8 *arg;
+ __le32 *next_bitmap;
+ u32 bitmap_shifter;
};
-/* temporary wext handlers */
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+/*
+ * Regulatory helper functions for wiphys
+ */
+
+/**
+ * regulatory_hint - driver hint to the wireless core a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ * conflicts)
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * should be in. If @rd is set this should be NULL. Note that if you
+ * set this to NULL you should still set rd->alpha2 to some accepted
+ * alpha2.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by
+ * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
+ * domain should be in or by providing a completely build regulatory domain.
+ * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
+ * for a regulatory domain structure for the respective country.
+ *
+ * The wiphy must have been registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM.
+ */
+extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ * conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+extern void regulatory_hint_11d(struct wiphy *wiphy,
+ u8 *country_ie,
+ u8 country_ie_len);
+/**
+ * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @regd: the custom regulatory domain to use for this wiphy
+ *
+ * Drivers can sometimes have custom regulatory domains which do not apply
+ * to a specific country. Drivers can use this to apply such custom regulatory
+ * domains. This routine must be called prior to wiphy registration. The
+ * custom regulatory domain will be trusted completely and as such previous
+ * default channel settings will be disregarded. If no rule is found for a
+ * channel on the regulatory domain the channel will be disabled.
+ */
+extern void wiphy_apply_custom_regulatory(
+ struct wiphy *wiphy,
+ const struct ieee80211_regdomain *regd);
+
+/**
+ * freq_reg_info - get regulatory information for the given frequency
+ * @wiphy: the wiphy for which we want to process this rule for
+ * @center_freq: Frequency in KHz for which we want regulatory information for
+ * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
+ * you can set this to 0. If this frequency is allowed we then set
+ * this value to the maximum allowed bandwidth.
+ * @reg_rule: the regulatory rule which we have for this frequency
+ *
+ * Use this function to get the regulatory rule for a specific frequency on
+ * a given wireless device. If the device has a specific regulatory domain
+ * it wants to follow we respect that unless a country IE has been received
+ * and processed already.
+ *
+ * Returns 0 if it was able to find a valid regulatory rule which does
+ * apply to the given center_freq otherwise it returns non-zero. It will
+ * also return -ERANGE if we determine the given center_freq does not even have
+ * a regulatory rule for a frequency range in the center_freq's band. See
+ * freq_in_rule_band() for our current definition of a band -- this is purely
+ * subjective and right now its 802.11 specific.
+ */
+extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
+ const struct ieee80211_reg_rule **reg_rule);
+
+/*
+ * Temporary wext handlers & helper functions
+ *
+ * In the future cfg80211 will simply assign the entire wext handler
+ * structure to netdevs it manages, but we're not there yet.
+ */
int cfg80211_wext_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra);
@@ -834,9 +1350,57 @@ int cfg80211_wext_siwscan(struct net_device *dev,
int cfg80211_wext_giwscan(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra);
+int cfg80211_wext_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
int cfg80211_wext_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra);
+int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_ibss_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_ibss_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_ibss_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_ibss_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+
+struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
+ struct iw_freq *freq);
+
+int cfg80211_wext_siwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra);
+int cfg80211_wext_giwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra);
+int cfg80211_wext_siwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra);
+int cfg80211_wext_giwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra);
+int cfg80211_wext_siwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra);
+int cfg80211_wext_giwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra);
+
+/*
+ * callbacks for asynchronous cfg80211 methods, notification
+ * functions and BSS handling helpers
+ */
/**
* cfg80211_scan_done - notify that scan finished
@@ -864,6 +1428,14 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp);
+struct cfg80211_bss*
+cfg80211_inform_bss(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *bssid,
+ u64 timestamp, u16 capability, u16 beacon_interval,
+ const u8 *ie, size_t ielen,
+ s32 signal, gfp_t gfp);
+
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
@@ -883,6 +1455,7 @@ struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
const u8 *meshid, size_t meshidlen,
const u8 *meshcfg);
void cfg80211_put_bss(struct cfg80211_bss *bss);
+
/**
* cfg80211_unlink_bss - unlink BSS from internal data structures
* @wiphy: the wiphy
@@ -902,44 +1475,62 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
* @len: length of the frame data
*
* This function is called whenever an authentication has been processed in
- * station mode.
+ * station mode. The driver is required to call either this function or
+ * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth()
+ * call.
*/
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
/**
+ * cfg80211_send_auth_timeout - notification of timed out authentication
+ * @dev: network device
+ * @addr: The MAC address of the device with which the authentication timed out
+ */
+void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
+
+/**
* cfg80211_send_rx_assoc - notification of processed association
* @dev: network device
* @buf: (re)association response frame (header + body)
* @len: length of the frame data
*
* This function is called whenever a (re)association response has been
- * processed in station mode.
+ * processed in station mode. The driver is required to call either this
+ * function or cfg80211_send_assoc_timeout() to indicate the result of
+ * cfg80211_ops::assoc() call.
*/
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
/**
- * cfg80211_send_rx_deauth - notification of processed deauthentication
+ * cfg80211_send_assoc_timeout - notification of timed out association
+ * @dev: network device
+ * @addr: The MAC address of the device with which the association timed out
+ */
+void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
+
+/**
+ * cfg80211_send_deauth - notification of processed deauthentication
* @dev: network device
* @buf: deauthentication frame (header + body)
* @len: length of the frame data
*
* This function is called whenever deauthentication has been processed in
- * station mode.
+ * station mode. This includes both received deauthentication frames and
+ * locally generated ones.
*/
-void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf,
- size_t len);
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
/**
- * cfg80211_send_rx_disassoc - notification of processed disassociation
+ * cfg80211_send_disassoc - notification of processed disassociation
* @dev: network device
* @buf: disassociation response frame (header + body)
* @len: length of the frame data
*
* This function is called whenever disassociation has been processed in
- * station mode.
+ * station mode. This includes both received disassociation frames and locally
+ * generated ones.
*/
-void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
- size_t len);
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
/**
* cfg80211_hold_bss - exclude bss from expiration
@@ -958,4 +1549,36 @@ void cfg80211_hold_bss(struct cfg80211_bss *bss);
*/
void cfg80211_unhold_bss(struct cfg80211_bss *bss);
+/**
+ * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
+ * @dev: network device
+ * @addr: The source MAC address of the frame
+ * @key_type: The key type that the received frame used
+ * @key_id: Key identifier (0..3)
+ * @tsc: The TSC value of the frame that generated the MIC failure (6 octets)
+ *
+ * This function is called whenever the local MAC detects a MIC failure in a
+ * received frame. This matches with MLME-MICHAELMICFAILURE.indication()
+ * primitive.
+ */
+void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
+ enum nl80211_key_type key_type, int key_id,
+ const u8 *tsc);
+
+/**
+ * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the IBSS joined
+ * @gfp: allocation flags
+ *
+ * This function notifies cfg80211 that the device joined an IBSS or
+ * switched to a different BSSID. Before this function can be called,
+ * either a beacon has to have been received from the IBSS, or one of
+ * the cfg80211_inform_bss{,_frame} functions must have been called
+ * with the locally generated beacon -- this guarantees that there is
+ * always a scan result for this IBSS. cfg80211 will handle the rest.
+ */
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
+
#endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 3b83a80e3fe..446dbf75a1c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,7 +19,6 @@
#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
-#include <net/wireless.h>
#include <net/cfg80211.h>
/**
@@ -518,7 +517,7 @@ struct ieee80211_rx_status {
* Flags to define PHY configuration options
*
* @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
- * @IEEE80211_CONF_PS: Enable 802.11 power save mode
+ * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only)
*/
enum ieee80211_conf_flags {
IEEE80211_CONF_RADIOTAP = (1<<0),
@@ -533,8 +532,7 @@ enum ieee80211_conf_flags {
* @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed
* @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
* @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
- * @IEEE80211_CONF_CHANGE_PS: the PS flag changed
- * @IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT: the dynamic PS timeout changed
+ * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
* @IEEE80211_CONF_CHANGE_POWER: the TX power changed
* @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed
* @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
@@ -545,10 +543,9 @@ enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2),
IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3),
IEEE80211_CONF_CHANGE_PS = BIT(4),
- IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT = BIT(5),
- IEEE80211_CONF_CHANGE_POWER = BIT(6),
- IEEE80211_CONF_CHANGE_CHANNEL = BIT(7),
- IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(8),
+ IEEE80211_CONF_CHANGE_POWER = BIT(5),
+ IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
+ IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
};
/**
@@ -556,14 +553,26 @@ enum ieee80211_conf_changed {
*
* This struct indicates how the driver shall configure the hardware.
*
+ * @flags: configuration flags defined above
+ *
* @radio_enabled: when zero, driver is required to switch off the radio.
* @beacon_int: beacon interval (TODO make interface config)
+ *
* @listen_interval: listen interval in units of beacon interval
- * @flags: configuration flags defined above
+ * @max_sleep_interval: the maximum number of beacon intervals to sleep for
+ * before checking the beacon for a TIM bit (managed mode only); this
+ * value will be only achievable between DTIM frames, the hardware
+ * needs to check for the multicast traffic bit in DTIM beacons.
+ * This variable is valid only when the CONF_PS flag is set.
+ * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
+ * powersave documentation below. This variable is valid only when
+ * the CONF_PS flag is set.
+ *
* @power_level: requested transmit power (in dBm)
- * @dynamic_ps_timeout: dynamic powersave timeout (in ms)
+ *
* @channel: the channel to tune to
* @channel_type: the channel (HT) type
+ *
* @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
* (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
* but actually means the number of transmissions not the number of retries
@@ -575,6 +584,7 @@ struct ieee80211_conf {
int beacon_int;
u32 flags;
int power_level, dynamic_ps_timeout;
+ int max_sleep_interval;
u16 listen_interval;
bool radio_enabled;
@@ -1109,11 +1119,9 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* need software support for parsing the TIM bitmap. This is also supported
* by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and
* %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still
- * required to pass up beacons. Additionally, in this case, mac80211 will
- * wake up the hardware when multicast traffic is announced in the beacon.
- *
- * FIXME: I don't think we can be fast enough in software when we want to
- * receive multicast traffic?
+ * required to pass up beacons. The hardware is still required to handle
+ * waking up for multicast traffic; if it cannot the driver must handle that
+ * as best as it can, mac80211 is too slow.
*
* Dynamic powersave mode is an extension to normal powersave mode in which
* the hardware stays awake for a user-specified period of time after sending
@@ -1134,11 +1142,53 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* way the host will only receive beacons where some relevant information
* (for example ERP protection or WMM settings) have changed.
*
- * Beacon filter support is informed with %IEEE80211_HW_BEACON_FILTER flag.
- * The driver needs to enable beacon filter support whenever power save is
- * enabled, that is %IEEE80211_CONF_PS is set. When power save is enabled,
- * the stack will not check for beacon miss at all and the driver needs to
- * notify about complete loss of beacons with ieee80211_beacon_loss().
+ * Beacon filter support is advertised with the %IEEE80211_HW_BEACON_FILTER
+ * hardware capability. The driver needs to enable beacon filter support
+ * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When
+ * power save is enabled, the stack will not check for beacon loss and the
+ * driver needs to notify about loss of beacons with ieee80211_beacon_loss().
+ *
+ * The time (or number of beacons missed) until the firmware notifies the
+ * driver of a beacon loss event (which in turn causes the driver to call
+ * ieee80211_beacon_loss()) should be configurable and will be controlled
+ * by mac80211 and the roaming algorithm in the future.
+ *
+ * Since there may be constantly changing information elements that nothing
+ * in the software stack cares about, we will, in the future, have mac80211
+ * tell the driver which information elements are interesting in the sense
+ * that we want to see changes in them. This will include
+ * - a list of information element IDs
+ * - a list of OUIs for the vendor information element
+ *
+ * Ideally, the hardware would filter out any beacons without changes in the
+ * requested elements, but if it cannot support that it may, at the expense
+ * of some efficiency, filter out only a subset. For example, if the device
+ * doesn't support checking for OUIs it should pass up all changes in all
+ * vendor information elements.
+ *
+ * Note that change, for the sake of simplification, also includes information
+ * elements appearing or disappearing from the beacon.
+ *
+ * Some hardware supports an "ignore list" instead, just make sure nothing
+ * that was requested is on the ignore list, and include commonly changing
+ * information element IDs in the ignore list, for example 11 (BSS load) and
+ * the various vendor-assigned IEs with unknown contents (128, 129, 133-136,
+ * 149, 150, 155, 156, 173, 176, 178, 179, 219); for forward compatibility
+ * it could also include some currently unused IDs.
+ *
+ *
+ * In addition to these capabilities, hardware should support notifying the
+ * host of changes in the beacon RSSI. This is relevant to implement roaming
+ * when no traffic is flowing (when traffic is flowing we see the RSSI of
+ * the received data packets). This can consist in notifying the host when
+ * the RSSI changes significantly or when it drops below or rises above
+ * configurable thresholds. In the future these thresholds will also be
+ * configured by mac80211 (which gets them from userspace) to implement
+ * them as the roaming algorithm requires.
+ *
+ * If the hardware cannot implement this, the driver should ask it to
+ * periodically pass beacon frames to the host so that software can do the
+ * signal strength threshold checking.
*/
/**
@@ -1330,11 +1380,14 @@ enum ieee80211_ampdu_mlme_action {
* the scan state machine in stack. The scan must honour the channel
* configuration done by the regulatory agent in the wiphy's
* registered bands. The hardware (or the driver) needs to make sure
- * that power save is disabled. When the scan finishes,
- * ieee80211_scan_completed() must be called; note that it also must
- * be called when the scan cannot finish because the hardware is
- * turned off! Anything else is a bug! Returns a negative error code
- * which will be seen in userspace.
+ * that power save is disabled.
+ * The @req ie/ie_len members are rewritten by mac80211 to contain the
+ * entire IEs after the SSID, so that drivers need not look at these
+ * at all but just send them after the SSID -- mac80211 includes the
+ * (extended) supported rates and HT information (where applicable).
+ * When the scan finishes, ieee80211_scan_completed() must be called;
+ * note that it also must be called when the scan cannot finish due to
+ * any error unless this callback returned a negative error code.
*
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
@@ -1572,6 +1625,20 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw);
*/
void ieee80211_free_hw(struct ieee80211_hw *hw);
+/**
+ * ieee80211_restart_hw - restart hardware completely
+ *
+ * Call this function when the hardware was restarted for some reason
+ * (hardware error, ...) and the driver is unable to restore its state
+ * by itself. mac80211 assumes that at this point the driver/hardware
+ * is completely uninitialised and stopped, it starts the process by
+ * calling the ->start() operation. The driver will need to reset all
+ * internal state that it has prior to calling this function.
+ *
+ * @hw: the hardware to restart
+ */
+void ieee80211_restart_hw(struct ieee80211_hw *hw);
+
/* trick to avoid symbol clashes with the ieee80211 subsystem */
void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_rx_status *status);
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
new file mode 100644
index 00000000000..47995b81c5d
--- /dev/null
+++ b/include/net/regulatory.h
@@ -0,0 +1,101 @@
+#ifndef __NET_REGULATORY_H
+#define __NET_REGULATORY_H
+/*
+ * regulatory support structures
+ *
+ * Copyright 2008-2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ *
+ * 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.
+ */
+
+
+/**
+ * enum environment_cap - Environment parsed from country IE
+ * @ENVIRON_ANY: indicates country IE applies to both indoor and
+ * outdoor operation.
+ * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation
+ * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation
+ */
+enum environment_cap {
+ ENVIRON_ANY,
+ ENVIRON_INDOOR,
+ ENVIRON_OUTDOOR,
+};
+
+/**
+ * struct regulatory_request - used to keep track of regulatory requests
+ *
+ * @wiphy_idx: this is set if this request's initiator is
+ * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
+ * can be used by the wireless core to deal with conflicts
+ * and potentially inform users of which devices specifically
+ * cased the conflicts.
+ * @initiator: indicates who sent this request, could be any of
+ * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
+ * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
+ * regulatory domain. We have a few special codes:
+ * 00 - World regulatory domain
+ * 99 - built by driver but a specific alpha2 cannot be determined
+ * 98 - result of an intersection between two regulatory domains
+ * @intersect: indicates whether the wireless core should intersect
+ * the requested regulatory domain with the presently set regulatory
+ * domain.
+ * @country_ie_checksum: checksum of the last processed and accepted
+ * country IE
+ * @country_ie_env: lets us know if the AP is telling us we are outdoor,
+ * indoor, or if it doesn't matter
+ * @list: used to insert into the reg_requests_list linked list
+ */
+struct regulatory_request {
+ int wiphy_idx;
+ enum nl80211_reg_initiator initiator;
+ char alpha2[2];
+ bool intersect;
+ u32 country_ie_checksum;
+ enum environment_cap country_ie_env;
+ struct list_head list;
+};
+
+struct ieee80211_freq_range {
+ u32 start_freq_khz;
+ u32 end_freq_khz;
+ u32 max_bandwidth_khz;
+};
+
+struct ieee80211_power_rule {
+ u32 max_antenna_gain;
+ u32 max_eirp;
+};
+
+struct ieee80211_reg_rule {
+ struct ieee80211_freq_range freq_range;
+ struct ieee80211_power_rule power_rule;
+ u32 flags;
+};
+
+struct ieee80211_regdomain {
+ u32 n_reg_rules;
+ char alpha2[2];
+ struct ieee80211_reg_rule reg_rules[];
+};
+
+#define MHZ_TO_KHZ(freq) ((freq) * 1000)
+#define KHZ_TO_MHZ(freq) ((freq) / 1000)
+#define DBI_TO_MBI(gain) ((gain) * 100)
+#define MBI_TO_DBI(gain) ((gain) / 100)
+#define DBM_TO_MBM(gain) ((gain) * 100)
+#define MBM_TO_DBM(gain) ((gain) / 100)
+
+#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \
+{ \
+ .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
+ .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
+ .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
+ .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\
+ .power_rule.max_eirp = DBM_TO_MBM(eirp), \
+ .flags = reg_flags, \
+}
+
+#endif
diff --git a/include/net/wireless.h b/include/net/wireless.h
deleted file mode 100644
index 64a76208580..00000000000
--- a/include/net/wireless.h
+++ /dev/null
@@ -1,472 +0,0 @@
-#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 <linux/ieee80211.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.
- * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
- * is not permitted.
- * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
- * is not permitted.
- */
-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,
- IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4,
- IEEE80211_CHAN_NO_FAT_BELOW = 1<<5,
-};
-
-/**
- * struct ieee80211_channel - channel definition
- *
- * This structure describes a single channel for use
- * with cfg80211.
- *
- * @center_freq: center frequency in MHz
- * @max_bandwidth: maximum allowed bandwidth for this channel, 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)
- * @beacon_found: helper to regulatory code to indicate when a beacon
- * has been found on this channel. Use regulatory_hint_found_beacon()
- * to enable this, this is is useful only on 5 GHz band.
- * @orig_mag: internal use
- * @orig_mpwr: internal use
- */
-struct ieee80211_channel {
- enum ieee80211_band band;
- u16 center_freq;
- u8 max_bandwidth;
- u16 hw_value;
- u32 flags;
- int max_antenna_gain;
- int max_power;
- bool beacon_found;
- 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_sta_ht_cap - 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 the STA
- * @cap: HT capabilities map as described in 802.11n spec
- * @ampdu_factor: Maximum A-MPDU length factor
- * @ampdu_density: Minimum A-MPDU spacing
- * @mcs: Supported MCS rates
- */
-struct ieee80211_sta_ht_cap {
- u16 cap; /* use IEEE80211_HT_CAP_ */
- bool ht_supported;
- u8 ampdu_factor;
- u8 ampdu_density;
- struct ieee80211_mcs_info mcs;
-};
-
-/**
- * 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_sta_ht_cap ht_cap;
-};
-
-/**
- * struct wiphy - wireless hardware description
- * @idx: the wiphy index assigned to this item
- * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
- * @custom_regulatory: tells us the driver for this device
- * has its own custom regulatory domain and cannot identify the
- * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- * we will disregard the first regulatory hint (when the
- * initiator is %REGDOM_SET_BY_CORE).
- * @strict_regulatory: tells us the driver for this device will ignore
- * regulatory domain settings until it gets its own regulatory domain
- * via its regulatory_hint(). After its gets its own regulatory domain
- * it will only allow further regulatory domain settings to further
- * enhance compliance. For example if channel 13 and 14 are disabled
- * by this regulatory domain no user regulatory domain can enable these
- * channels at a later time. This can be used for devices which do not
- * have calibration information gauranteed for frequencies or settings
- * outside of its regulatory domain.
- * @reg_notifier: the driver's regulatory notification callback
- * @regd: the driver's regulatory domain, if one was requested via
- * the regulatory_hint() API. This can be used by the driver
- * on the reg_notifier() if it chooses to ignore future
- * regulatory domain changes caused by other drivers.
- * @signal_type: signal type reported in &struct cfg80211_bss.
- */
-struct wiphy {
- /* assign these fields before you register the wiphy */
-
- /* permanent MAC address */
- u8 perm_addr[ETH_ALEN];
-
- /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
- u16 interface_modes;
-
- bool custom_regulatory;
- bool strict_regulatory;
-
- enum cfg80211_signal_type signal_type;
-
- int bss_priv_size;
- u8 max_scan_ssids;
-
- /* 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];
-
- /* Lets us get back the wiphy on the callback */
- int (*reg_notifier)(struct wiphy *wiphy,
- struct regulatory_request *request);
-
- /* fields below are read-only, assigned by cfg80211 */
-
- const struct ieee80211_regdomain *regd;
-
- /* 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
- * @iftype: interface type
- */
-struct wireless_dev {
- struct wiphy *wiphy;
- enum nl80211_iftype iftype;
-
- /* 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 const char *wiphy_name(struct wiphy *wiphy)
-{
- return dev_name(&wiphy->dev);
-}
-
-/**
- * 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);
-
-/*
- * Name indirection necessary because the ieee80211 code also has
- * a function named "ieee80211_get_channel", so if you include
- * cfg80211's header file you get cfg80211's version, if you try
- * to include both header files you'll (rightfully!) get a symbol
- * clash.
- */
-extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
- int freq);
-/**
- * ieee80211_get_channel - get channel struct from wiphy for specified frequency
- */
-static inline struct ieee80211_channel *
-ieee80211_get_channel(struct wiphy *wiphy, int freq)
-{
- return __ieee80211_get_channel(wiphy, freq);
-}
-
-/**
- * ieee80211_get_response_rate - get basic rate for a given rate
- *
- * @sband: the band to look for rates in
- * @basic_rates: bitmap of basic rates
- * @bitrate: the bitrate for which to find the basic rate
- *
- * This function returns the basic rate corresponding to a given
- * bitrate, that is the next lower bitrate contained in the basic
- * rate map, which is, for this function, given as a bitmap of
- * indices of rates in the band's bitrate table.
- */
-struct ieee80211_rate *
-ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
- u32 basic_rates, int bitrate);
-
-/**
- * regulatory_hint - driver hint to the wireless core a regulatory domain
- * @wiphy: the wireless device giving the hint (used only for reporting
- * conflicts)
- * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
- * should be in. If @rd is set this should be NULL. Note that if you
- * set this to NULL you should still set rd->alpha2 to some accepted
- * alpha2.
- *
- * Wireless drivers can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain by
- * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
- * domain should be in or by providing a completely build regulatory domain.
- * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
- * for a regulatory domain structure for the respective country.
- *
- * The wiphy must have been registered to cfg80211 prior to this call.
- * For cfg80211 drivers this means you must first use wiphy_register(),
- * for mac80211 drivers you must first use ieee80211_register_hw().
- *
- * Drivers should check the return value, its possible you can get
- * an -ENOMEM.
- */
-extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
-
-/**
- * regulatory_hint_11d - hints a country IE as a regulatory domain
- * @wiphy: the wireless device giving the hint (used only for reporting
- * conflicts)
- * @country_ie: pointer to the country IE
- * @country_ie_len: length of the country IE
- *
- * We will intersect the rd with the what CRDA tells us should apply
- * for the alpha2 this country IE belongs to, this prevents APs from
- * sending us incorrect or outdated information against a country.
- */
-extern void regulatory_hint_11d(struct wiphy *wiphy,
- u8 *country_ie,
- u8 country_ie_len);
-/**
- * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
- * @wiphy: the wireless device we want to process the regulatory domain on
- * @regd: the custom regulatory domain to use for this wiphy
- *
- * Drivers can sometimes have custom regulatory domains which do not apply
- * to a specific country. Drivers can use this to apply such custom regulatory
- * domains. This routine must be called prior to wiphy registration. The
- * custom regulatory domain will be trusted completely and as such previous
- * default channel settings will be disregarded. If no rule is found for a
- * channel on the regulatory domain the channel will be disabled.
- */
-extern void wiphy_apply_custom_regulatory(
- struct wiphy *wiphy,
- const struct ieee80211_regdomain *regd);
-
-/**
- * freq_reg_info - get regulatory information for the given frequency
- * @wiphy: the wiphy for which we want to process this rule for
- * @center_freq: Frequency in KHz for which we want regulatory information for
- * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
- * you can set this to 0. If this frequency is allowed we then set
- * this value to the maximum allowed bandwidth.
- * @reg_rule: the regulatory rule which we have for this frequency
- *
- * Use this function to get the regulatory rule for a specific frequency on
- * a given wireless device. If the device has a specific regulatory domain
- * it wants to follow we respect that unless a country IE has been received
- * and processed already.
- *
- * Returns 0 if it was able to find a valid regulatory rule which does
- * apply to the given center_freq otherwise it returns non-zero. It will
- * also return -ERANGE if we determine the given center_freq does not even have
- * a regulatory rule for a frequency range in the center_freq's band. See
- * freq_in_rule_band() for our current definition of a band -- this is purely
- * subjective and right now its 802.11 specific.
- */
-extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
- const struct ieee80211_reg_rule **reg_rule);
-
-#endif /* __NET_WIRELESS_H */
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index ecc3faf9f11..9cbf545e95a 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -11,6 +11,22 @@ config MAC80211
This option enables the hardware independent IEEE 802.11
networking stack.
+config MAC80211_DEFAULT_PS
+ bool "enable powersave by default"
+ depends on MAC80211
+ default y
+ help
+ This option enables powersave mode by default.
+
+ If this causes your applications to misbehave you should fix your
+ applications instead -- they need to register their network
+ latency requirement, see Documentation/power/pm_qos_interface.txt.
+
+config MAC80211_DEFAULT_PS_VALUE
+ int
+ default 1 if MAC80211_DEFAULT_PS
+ default 0
+
menu "Rate control algorithm selection"
depends on MAC80211 != n
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e677b751d46..5e1c230744b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1167,7 +1167,8 @@ static int ieee80211_scan(struct wiphy *wiphy,
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon))
return -EOPNOTSUPP;
return ieee80211_request_scan(sdata, req);
@@ -1267,25 +1268,62 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_deauth_request *req)
{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- /* TODO: req->ie */
+ /* TODO: req->ie, req->peer_addr */
return ieee80211_sta_deauthenticate(sdata, req->reason_code);
}
static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_disassoc_request *req)
{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- /* TODO: req->ie */
+ /* TODO: req->ie, req->peer_addr */
return ieee80211_sta_disassociate(sdata, req->reason_code);
}
+static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ return ieee80211_ibss_join(sdata, params);
+}
+
+static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ return ieee80211_ibss_leave(sdata);
+}
+
+static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ int err;
+
+ if (local->ops->set_rts_threshold) {
+ err = local->ops->set_rts_threshold(
+ local_to_hw(local), wiphy->rts_threshold);
+ if (err)
+ return err;
+ }
+ }
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT)
+ local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
+ if (changed & WIPHY_PARAM_RETRY_LONG)
+ local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
+ if (changed &
+ (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG))
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1322,4 +1360,7 @@ struct cfg80211_ops mac80211_config_ops = {
.assoc = ieee80211_assoc,
.deauth = ieee80211_deauth,
.disassoc = ieee80211_disassoc,
+ .join_ibss = ieee80211_join_ibss,
+ .leave_ibss = ieee80211_leave_ibss,
+ .set_wiphy_params = ieee80211_set_wiphy_params,
};
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 210b9b6fecd..5001328be46 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -52,13 +52,13 @@ static const struct file_operations name## _ops = { \
DEBUGFS_READONLY_FILE(frequency, 20, "%d",
local->hw.conf.channel->center_freq);
DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
- local->rts_threshold);
+ local->hw.wiphy->rts_threshold);
DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
- local->fragmentation_threshold);
+ local->hw.wiphy->frag_threshold);
DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
- local->hw.conf.short_frame_max_tx_count);
+ local->hw.wiphy->retry_short);
DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
- local->hw.conf.long_frame_max_tx_count);
+ local->hw.wiphy->retry_long);
DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
local->total_ps_buffered);
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
diff --git a/net/mac80211/event.c b/net/mac80211/event.c
index 0d95561c0ee..f288d01a634 100644
--- a/net/mac80211/event.c
+++ b/net/mac80211/event.c
@@ -12,12 +12,12 @@
#include "ieee80211_i.h"
/*
- * indicate a failed Michael MIC to userspace; the passed packet
- * (in the variable hdr) must be long enough to extract the TKIP
- * fields like TSC
+ * Indicate a failed Michael MIC to userspace. If the caller knows the TSC of
+ * the frame that generated the MIC failure (i.e., if it was provided by the
+ * driver or is still in the frame), it should provide that information.
*/
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_hdr *hdr, const u8 *tsc)
{
union iwreq_data wrqu;
char *buf = kmalloc(128, GFP_ATOMIC);
@@ -34,8 +34,9 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
kfree(buf);
}
- /*
- * TODO: re-add support for sending MIC failure indication
- * with all info via nl80211
- */
+ cfg80211_michael_mic_failure(sdata->dev, hdr->addr2,
+ (hdr->addr1[0] & 0x01) ?
+ NL80211_KEYTYPE_GROUP :
+ NL80211_KEYTYPE_PAIRWISE,
+ keyidx, tsc);
}
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 4e3c72f20de..0891bfb0699 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -14,7 +14,6 @@
*/
#include <linux/ieee80211.h>
-#include <net/wireless.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "rate.h"
@@ -83,89 +82,6 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
ht_cap->mcs.rx_mask[32/8] |= 1;
}
-/*
- * ieee80211_enable_ht should be called only after the operating band
- * has been determined as ht configuration depends on the hw's
- * HT abilities for a specific band.
- */
-u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_ht_info *hti,
- u16 ap_ht_cap_flags)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_bss_ht_conf ht;
- struct sta_info *sta;
- u32 changed = 0;
- bool enable_ht = true, ht_changed;
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- memset(&ht, 0, sizeof(ht));
-
- /* HT is not supported */
- if (!sband->ht_cap.ht_supported)
- enable_ht = false;
-
- /* check that channel matches the right operating channel */
- if (local->hw.conf.channel->center_freq !=
- ieee80211_channel_to_frequency(hti->control_chan))
- enable_ht = false;
-
- if (enable_ht) {
- channel_type = NL80211_CHAN_HT20;
-
- if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
- (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
- (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
- switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- channel_type = NL80211_CHAN_HT40PLUS;
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- channel_type = NL80211_CHAN_HT40MINUS;
- break;
- }
- }
- }
-
- ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
- channel_type != local->hw.conf.channel_type;
-
- local->oper_channel_type = channel_type;
-
- if (ht_changed) {
- /* channel_type change automatically detected */
- ieee80211_hw_config(local, 0);
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ifmgd->bssid);
- if (sta)
- rate_control_rate_update(local, sband, sta,
- IEEE80211_RC_HT_CHANGED);
-
- rcu_read_unlock();
-
- }
-
- /* disable HT */
- if (!enable_ht)
- return 0;
-
- ht.operation_mode = le16_to_cpu(hti->operation_mode);
-
- /* if bss configuration changed store the new one */
- if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
- changed |= BSS_CHANGED_HT;
- sdata->vif.bss_conf.ht = ht;
- }
-
- return changed;
-}
-
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
{
int i;
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3201e1f9636..6030e003180 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -59,74 +59,59 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.bssid, 0);
}
-static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
- const u8 *bssid, const int beacon_int,
- const int freq,
- const size_t supp_rates_len,
- const u8 *supp_rates,
- const u16 capability, u64 tsf)
+static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid, const int beacon_int,
+ struct ieee80211_channel *chan,
+ const size_t supp_rates_len,
+ const u8 *supp_rates,
+ const u16 capability, u64 tsf)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
- int res = 0, rates, i, j;
+ int rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
- union iwreq_data wrqu;
if (local->ops->reset_tsf) {
/* Reset own TSF to allow time synchronization work. */
local->ops->reset_tsf(local_to_hw(local));
}
- if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) &&
- memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0)
- return res;
+ skb = ifibss->skb;
+ rcu_assign_pointer(ifibss->presp, NULL);
+ synchronize_rcu();
+ skb->data = skb->head;
+ skb->len = 0;
+ skb_reset_tail_pointer(skb);
+ skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
- "response\n", sdata->dev->name);
- return -ENOMEM;
- }
-
- if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) {
- /* Remove possible STA entries from other IBSS networks. */
- sta_info_flush_delayed(sdata);
- }
+ if (memcmp(ifibss->bssid, bssid, ETH_ALEN))
+ sta_info_flush(sdata->local, sdata);
memcpy(ifibss->bssid, bssid, ETH_ALEN);
- res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
- if (res)
- return res;
local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
- sdata->drop_unencrypted = capability &
- WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
- res = ieee80211_set_freq(sdata, freq);
+ sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
- if (res)
- return res;
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ local->oper_channel = chan;
+ local->oper_channel_type = NL80211_CHAN_NO_HT;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+ sband = local->hw.wiphy->bands[chan->band];
/* Build IBSS probe response */
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- mgmt = (struct ieee80211_mgmt *)
- skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
memset(mgmt->da, 0xff, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
- mgmt->u.beacon.beacon_int =
- cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int);
mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
mgmt->u.beacon.capab_info = cpu_to_le16(capability);
@@ -147,7 +132,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2 + 1);
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(freq);
+ *pos++ = ieee80211_frequency_to_channel(chan->center_freq);
}
pos = skb_put(skb, 2 + 2);
@@ -165,12 +150,15 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, &supp_rates[8], rates);
}
- ifibss->probe_resp = skb;
+ if (ifibss->ie_len)
+ memcpy(skb_put(skb, ifibss->ie_len),
+ ifibss->ie, ifibss->ie_len);
+
+ rcu_assign_pointer(ifibss->presp, skb);
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
IEEE80211_IFCC_BEACON_ENABLED);
-
rates = 0;
for (i = 0; i < supp_rates_len; i++) {
int bitrate = (supp_rates[i] & 0x7f) * 5;
@@ -181,27 +169,24 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
- ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET;
ifibss->state = IEEE80211_IBSS_MLME_JOINED;
- mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+ mod_timer(&ifibss->timer,
+ round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
- wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
-
- return res;
+ cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
+ mgmt, skb->len, 0, GFP_KERNEL);
+ cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
}
-static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss *bss)
+static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss *bss)
{
- return __ieee80211_sta_join_ibss(sdata,
- bss->cbss.bssid,
- bss->cbss.beacon_interval,
- bss->cbss.channel->center_freq,
- bss->supp_rates_len, bss->supp_rates,
- bss->cbss.capability,
- bss->cbss.tsf);
+ __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
+ bss->cbss.beacon_interval,
+ bss->cbss.channel,
+ bss->supp_rates_len, bss->supp_rates,
+ bss->cbss.capability,
+ bss->cbss.tsf);
}
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -277,7 +262,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
goto put_bss;
/* we use a fixed BSSID */
- if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET)
+ if (sdata->u.ibss.bssid)
goto put_bss;
/* not an IBSS */
@@ -369,13 +354,14 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
int band = local->hw.conf.channel->band;
- /* TODO: Could consider removing the least recently used entry and
- * allow new one to be added. */
+ /*
+ * XXX: Consider removing the least recently used entry and
+ * allow new one to be added.
+ */
if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: No room for a new IBSS STA "
- "entry %pM\n", sdata->dev->name, addr);
- }
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
+ sdata->dev->name, addr);
return NULL;
}
@@ -432,14 +418,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+ mod_timer(&ifibss->timer,
+ round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
+
if (ieee80211_sta_active_ibss(sdata))
return;
- if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) &&
- (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL)))
+ if (ifibss->fixed_channel)
return;
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
@@ -455,7 +442,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
}
-static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@@ -466,7 +453,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
u16 capability;
int i;
- if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) {
+ if (ifibss->fixed_bssid) {
memcpy(bssid, ifibss->bssid, ETH_ALEN);
} else {
/* Generate random, not broadcast, locally administered BSSID. Mix in
@@ -482,7 +469,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
sdata->dev->name, bssid);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[ifibss->channel->band];
if (local->hw.conf.beacon_int == 0)
local->hw.conf.beacon_int = 100;
@@ -500,24 +487,20 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
*pos++ = (u8) (rate / 5);
}
- return __ieee80211_sta_join_ibss(sdata,
- bssid, local->hw.conf.beacon_int,
- local->hw.conf.channel->center_freq,
- sband->n_bitrates, supp_rates,
- capability, 0);
+ __ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int,
+ ifibss->channel, sband->n_bitrates,
+ supp_rates, capability, 0);
}
-static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss *bss;
+ struct ieee80211_channel *chan = NULL;
const u8 *bssid = NULL;
int active_ibss;
- if (ifibss->ssid_len == 0)
- return -EINVAL;
-
active_ibss = ieee80211_sta_active_ibss(sdata);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
@@ -525,11 +508,15 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (active_ibss)
- return 0;
+ return;
- if (ifibss->flags & IEEE80211_IBSS_BSSID_SET)
+ if (ifibss->fixed_bssid)
+ bssid = ifibss->bssid;
+ if (ifibss->fixed_channel)
+ chan = ifibss->channel;
+ if (!is_zero_ether_addr(ifibss->bssid))
bssid = ifibss->bssid;
- bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid,
+ bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
WLAN_CAPABILITY_IBSS,
WLAN_CAPABILITY_IBSS);
@@ -540,18 +527,14 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
"%pM\n", bss->cbss.bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (bss &&
- (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) ||
- memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) {
- int ret;
-
+ if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
sdata->dev->name, bss->cbss.bssid);
- ret = ieee80211_sta_join_ibss(sdata, bss);
+ ieee80211_sta_join_ibss(sdata, bss);
ieee80211_rx_bss_put(local, bss);
- return ret;
+ return;
} else if (bss)
ieee80211_rx_bss_put(local, bss);
@@ -562,29 +545,31 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
/* Selected IBSS not found in current scan results - try to scan */
if (ifibss->state == IEEE80211_IBSS_MLME_JOINED &&
!ieee80211_sta_active_ibss(sdata)) {
- mod_timer(&ifibss->timer, jiffies +
- IEEE80211_IBSS_MERGE_INTERVAL);
- } else if (time_after(jiffies, local->last_scan_completed +
+ mod_timer(&ifibss->timer,
+ round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
+ } else if (time_after(jiffies, ifibss->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) {
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
"join\n", sdata->dev->name);
/* XXX maybe racy? */
if (local->scan_req)
- return -EBUSY;
+ return;
memcpy(local->int_scan_req.ssids[0].ssid,
ifibss->ssid, IEEE80211_MAX_SSID_LEN);
- local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len;
- return ieee80211_request_scan(sdata, &local->int_scan_req);
+ local->int_scan_req.ssids[0].ssid_len =
+ ifibss->ssid_len;
+ ieee80211_request_scan(sdata, &local->int_scan_req);
} else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
int interval = IEEE80211_SCAN_INTERVAL;
if (time_after(jiffies, ifibss->ibss_join_req +
IEEE80211_IBSS_JOIN_TIMEOUT)) {
- if (!(local->oper_channel->flags &
- IEEE80211_CHAN_NO_IBSS))
- return ieee80211_sta_create_ibss(sdata);
+ if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) {
+ ieee80211_sta_create_ibss(sdata);
+ return;
+ }
printk(KERN_DEBUG "%s: IBSS not allowed on"
" %d MHz\n", sdata->dev->name,
local->hw.conf.channel->center_freq);
@@ -595,11 +580,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
}
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
- mod_timer(&ifibss->timer, jiffies + interval);
- return 0;
+ mod_timer(&ifibss->timer,
+ round_jiffies(jiffies + interval));
}
-
- return 0;
}
static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
@@ -614,7 +597,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
u8 *pos, *end;
if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
- len < 24 + 2 || !ifibss->probe_resp)
+ len < 24 + 2 || !ifibss->presp)
return;
if (local->ops->tx_last_beacon)
@@ -649,13 +632,13 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
}
if (pos[1] != 0 &&
(pos[1] != ifibss->ssid_len ||
- memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) {
+ !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) {
/* Ignore ProbeReq for foreign SSID */
return;
}
/* Reply with ProbeResp */
- skb = skb_copy(ifibss->probe_resp, GFP_KERNEL);
+ skb = skb_copy(ifibss->presp, GFP_KERNEL);
if (!skb)
return;
@@ -794,89 +777,21 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
setup_timer(&ifibss->timer, ieee80211_ibss_timer,
(unsigned long) sdata);
skb_queue_head_init(&ifibss->skb_queue);
-
- ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |
- IEEE80211_IBSS_AUTO_CHANNEL_SEL;
-}
-
-int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET;
-
- if (ifibss->ssid_len)
- ifibss->flags |= IEEE80211_IBSS_SSID_SET;
- else
- ifibss->flags &= ~IEEE80211_IBSS_SSID_SET;
-
- ifibss->ibss_join_req = jiffies;
- ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
- set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
-
- return 0;
-}
-
-int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- if (len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
-
- if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) {
- memset(ifibss->ssid, 0, sizeof(ifibss->ssid));
- memcpy(ifibss->ssid, ssid, len);
- ifibss->ssid_len = len;
- }
-
- return ieee80211_ibss_commit(sdata);
-}
-
-int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- memcpy(ssid, ifibss->ssid, ifibss->ssid_len);
- *len = ifibss->ssid_len;
-
- return 0;
-}
-
-int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- if (is_valid_ether_addr(bssid)) {
- memcpy(ifibss->bssid, bssid, ETH_ALEN);
- ifibss->flags |= IEEE80211_IBSS_BSSID_SET;
- } else {
- memset(ifibss->bssid, 0, ETH_ALEN);
- ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET;
- }
-
- if (netif_running(sdata->dev)) {
- if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) {
- printk(KERN_DEBUG "%s: Failed to config new BSSID to "
- "the low-level driver\n", sdata->dev->name);
- }
- }
-
- return ieee80211_ibss_commit(sdata);
}
/* scan finished notification */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
{
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- struct ieee80211_if_ibss *ifibss;
+ struct ieee80211_sub_if_data *sdata;
- if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- ifibss = &sdata->u.ibss;
- if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) ||
- !ieee80211_sta_active_ibss(sdata))
- ieee80211_sta_find_ibss(sdata);
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ continue;
+ sdata->u.ibss.last_scan_completed = jiffies;
+ ieee80211_sta_find_ibss(sdata);
}
+ mutex_unlock(&local->iflist_mtx);
}
ieee80211_rx_result
@@ -906,3 +821,71 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
return RX_DROP_MONITOR;
}
+
+int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_ibss_params *params)
+{
+ struct sk_buff *skb;
+
+ memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
+ sdata->u.ibss.ssid_len = params->ssid_len;
+
+ if (params->bssid) {
+ memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
+ sdata->u.ibss.fixed_bssid = true;
+ } else
+ sdata->u.ibss.fixed_bssid = false;
+
+ sdata->u.ibss.channel = params->channel;
+ sdata->u.ibss.fixed_channel = params->channel_fixed;
+
+ if (params->ie) {
+ sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
+ GFP_KERNEL);
+ if (sdata->u.ibss.ie)
+ sdata->u.ibss.ie_len = params->ie_len;
+ }
+
+ skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
+ 36 /* bitrates */ +
+ 34 /* SSID */ +
+ 3 /* DS params */ +
+ 4 /* IBSS params */ +
+ params->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ sdata->u.ibss.skb = skb;
+ sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
+ sdata->u.ibss.ibss_join_req = jiffies;
+
+ set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+ queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
+
+ return 0;
+}
+
+int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
+{
+ struct sk_buff *skb;
+
+ del_timer_sync(&sdata->u.ibss.timer);
+ clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+ cancel_work_sync(&sdata->u.ibss.work);
+ clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+
+ sta_info_flush(sdata->local, sdata);
+
+ /* remove beacon */
+ kfree(sdata->u.ibss.ie);
+ skb = sdata->u.ibss.presp;
+ rcu_assign_pointer(sdata->u.ibss.presp, NULL);
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+ synchronize_rcu();
+ kfree_skb(skb);
+
+ skb_queue_purge(&sdata->u.ibss.skb_queue);
+ memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
+
+ return 0;
+}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e6ed78cb16b..1579bc92c88 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -24,7 +24,6 @@
#include <linux/spinlock.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#include <net/wireless.h>
#include <net/iw_handler.h>
#include <net/mac80211.h>
#include "key.h"
@@ -295,6 +294,8 @@ struct ieee80211_if_managed {
int auth_tries; /* retries for auth req */
int assoc_tries; /* retries for assoc req */
+ bool powersave; /* powersave requested for this iface */
+
unsigned long request;
unsigned long last_probe;
@@ -306,6 +307,8 @@ struct ieee80211_if_managed {
int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
int auth_transaction;
+ u32 beacon_crc;
+
enum {
IEEE80211_MFP_DISABLED,
IEEE80211_MFP_OPTIONAL,
@@ -319,14 +322,6 @@ struct ieee80211_if_managed {
size_t sme_auth_ie_len;
};
-enum ieee80211_ibss_flags {
- IEEE80211_IBSS_AUTO_CHANNEL_SEL = BIT(0),
- IEEE80211_IBSS_AUTO_BSSID_SEL = BIT(1),
- IEEE80211_IBSS_BSSID_SET = BIT(2),
- IEEE80211_IBSS_PREV_BSSID_SET = BIT(3),
- IEEE80211_IBSS_SSID_SET = BIT(4),
-};
-
enum ieee80211_ibss_request {
IEEE80211_IBSS_REQ_RUN = 0,
};
@@ -337,17 +332,20 @@ struct ieee80211_if_ibss {
struct sk_buff_head skb_queue;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- u8 ssid_len;
-
- u32 flags;
+ unsigned long request;
+ unsigned long last_scan_completed;
+ bool fixed_bssid;
+ bool fixed_channel;
u8 bssid[ETH_ALEN];
-
- unsigned long request;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len, ie_len;
+ u8 *ie;
+ struct ieee80211_channel *channel;
unsigned long ibss_join_req;
- struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
+ /* probe response/beacon for IBSS */
+ struct sk_buff *presp, *skb;
enum {
IEEE80211_IBSS_MLME_SEARCH,
@@ -626,8 +624,6 @@ struct ieee80211_local {
spinlock_t sta_lock;
unsigned long num_sta;
struct list_head sta_list;
- struct list_head sta_flush_list;
- struct work_struct sta_flush_work;
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
@@ -647,9 +643,6 @@ struct ieee80211_local {
struct rate_control_ref *rate_ctrl;
- int rts_threshold;
- int fragmentation_threshold;
-
struct crypto_blkcipher *wep_tx_tfm;
struct crypto_blkcipher *wep_rx_tfm;
u32 wep_iv;
@@ -671,10 +664,12 @@ struct ieee80211_local {
struct cfg80211_scan_request int_scan_req;
struct cfg80211_scan_request *scan_req;
struct ieee80211_channel *scan_channel;
+ const u8 *orig_ies;
+ int orig_ies_len;
int scan_channel_idx;
+ int scan_ies_len;
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
- unsigned long last_scan_completed;
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type;
@@ -736,15 +731,22 @@ struct ieee80211_local {
int wifi_wme_noack_test;
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
- bool powersave;
bool pspolling;
+ /*
+ * PS can only be enabled when we have exactly one managed
+ * interface (and monitors) in PS, this then points there.
+ */
+ struct ieee80211_sub_if_data *ps_sdata;
struct work_struct dynamic_ps_enable_work;
struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer;
+ struct notifier_block network_latency_notifier;
int user_power_level; /* in dBm */
int power_constr_level; /* in dBm */
+ struct work_struct restart_work;
+
#ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries {
struct dentry *rcdir;
@@ -830,7 +832,7 @@ struct ieee802_11_elems {
u8 *fh_params;
u8 *ds_params;
u8 *cf_params;
- u8 *tim;
+ struct ieee80211_tim_ie *tim;
u8 *ibss_params;
u8 *challenge;
u8 *wpa;
@@ -927,12 +929,11 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason
int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
+void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
+int ieee80211_max_network_latency(struct notifier_block *nb,
+ unsigned long data, void *dummy);
/* IBSS code */
-int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata);
-int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
-int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
-int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
ieee80211_rx_result
@@ -940,6 +941,9 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status);
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
u8 *bssid, u8 *addr, u32 supp_rates);
+int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_ibss_params *params);
+int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
@@ -995,9 +999,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap);
-u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_ht_info *hti,
- u16 ap_ht_cap_flags);
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
@@ -1036,15 +1037,22 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
u16 capab_info, u8 *pwr_constr_elem,
u8 pwr_constr_elem_len);
-/* Suspend/resume */
+/* Suspend/resume and hw reconfiguration */
+int ieee80211_reconfig(struct ieee80211_local *local);
+
#ifdef CONFIG_PM
int __ieee80211_suspend(struct ieee80211_hw *hw);
-int __ieee80211_resume(struct ieee80211_hw *hw);
+
+static inline int __ieee80211_resume(struct ieee80211_hw *hw)
+{
+ return ieee80211_reconfig(hw_to_local(hw));
+}
#else
static inline int __ieee80211_suspend(struct ieee80211_hw *hw)
{
return 0;
}
+
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
{
return 0;
@@ -1060,12 +1068,15 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
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 ieee80211_sub_if_data *sdata, int keyidx,
- struct ieee80211_hdr *hdr);
+ struct ieee80211_hdr *hdr, const u8 *tsc);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
int encrypt);
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems);
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ u64 filter, u32 crc);
int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band);
@@ -1093,9 +1104,11 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
u8 *extra, size_t extra_len,
const u8 *bssid, int encrypt);
+int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
+ const u8 *ie, size_t ie_len);
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
- u8 *ssid, size_t ssid_len,
- u8 *ie, size_t ie_len);
+ const u8 *ssid, size_t ssid_len,
+ const u8 *ie, size_t ie_len);
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 91e8e1bacaa..52425975bbb 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -235,11 +235,7 @@ static int ieee80211_open(struct net_device *dev)
netif_addr_unlock_bh(local->mdev);
break;
case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- else
- sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET;
+ sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
/* fall through */
default:
conf.vif = &sdata->vif;
@@ -317,6 +313,8 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_set_wmm_default(sdata);
}
+ ieee80211_recalc_ps(local, -1);
+
/*
* ieee80211_sta_work is disabled while network interface
* is down. Therefore, some configuration changes may not
@@ -325,8 +323,6 @@ static int ieee80211_open(struct net_device *dev)
*/
if (sdata->vif.type == NL80211_IFTYPE_STATION)
queue_work(local->hw.workqueue, &sdata->u.mgd.work);
- else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- queue_work(local->hw.workqueue, &sdata->u.ibss.work);
netif_tx_start_all_queues(dev);
@@ -497,7 +493,6 @@ static int ieee80211_stop(struct net_device *dev)
/* fall through */
case NL80211_IFTYPE_ADHOC:
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
del_timer_sync(&sdata->u.ibss.timer);
cancel_work_sync(&sdata->u.ibss.work);
synchronize_rcu();
@@ -572,6 +567,8 @@ static int ieee80211_stop(struct net_device *dev)
hw_reconf_flags = 0;
}
+ ieee80211_recalc_ps(local, -1);
+
/* do after stop to avoid reconfiguring when we stop anyway */
if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags);
@@ -649,7 +646,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
mesh_rmc_free(sdata);
break;
case NL80211_IFTYPE_ADHOC:
- kfree_skb(sdata->u.ibss.probe_resp);
+ if (WARN_ON(sdata->u.ibss.presp))
+ kfree_skb(sdata->u.ibss.presp);
break;
case NL80211_IFTYPE_STATION:
kfree(sdata->u.mgd.extra_ie);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index fbcbed6cad0..5320e08434a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -21,6 +21,7 @@
#include <linux/wireless.h>
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
+#include <linux/pm_qos_params.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -208,7 +209,7 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
!!rcu_dereference(sdata->u.ap.beacon);
break;
case NL80211_IFTYPE_ADHOC:
- conf.enable_beacon = !!sdata->u.ibss.probe_resp;
+ conf.enable_beacon = !!sdata->u.ibss.presp;
break;
case NL80211_IFTYPE_MESH_POINT:
conf.enable_beacon = true;
@@ -696,6 +697,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
EXPORT_SYMBOL(ieee80211_tx_status);
+static void ieee80211_restart_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local, restart_work);
+
+ rtnl_lock();
+ ieee80211_reconfig(local);
+ rtnl_unlock();
+}
+
+void ieee80211_restart_hw(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ /* use this reason, __ieee80211_resume will unblock it */
+ ieee80211_stop_queues_by_reason(hw,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+
+ schedule_work(&local->restart_work);
+}
+EXPORT_SYMBOL(ieee80211_restart_hw);
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -728,12 +751,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
return NULL;
wiphy->privid = mac80211_wiphy_privid;
- wiphy->max_scan_ssids = 4;
+
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
sizeof(struct cfg80211_bss);
local = wiphy_priv(wiphy);
+
local->hw.wiphy = wiphy;
local->hw.priv = (char *)local +
@@ -752,10 +776,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
/* set up some defaults */
local->hw.queues = 1;
local->hw.max_rates = 1;
- local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
- local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
- local->hw.conf.long_frame_max_tx_count = 4;
- local->hw.conf.short_frame_max_tx_count = 7;
+ local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
+ local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
local->hw.conf.radio_enabled = true;
INIT_LIST_HEAD(&local->interfaces);
@@ -767,6 +789,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
+ INIT_WORK(&local->restart_work, ieee80211_restart_work);
+
INIT_WORK(&local->dynamic_ps_enable_work,
ieee80211_dynamic_ps_enable_work);
INIT_WORK(&local->dynamic_ps_disable_work,
@@ -820,7 +844,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
enum ieee80211_band band;
struct net_device *mdev;
struct ieee80211_master_priv *mpriv;
- int channels, i, j;
+ int channels, i, j, max_bitrates;
+ bool supp_ht;
+ static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+
+ /* keep last -- depends on hw flags! */
+ WLAN_CIPHER_SUITE_AES_CMAC
+ };
/*
* generic code guarantees at least one band,
@@ -828,18 +862,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
* that hw.conf.channel is assigned
*/
channels = 0;
+ max_bitrates = 0;
+ supp_ht = false;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
sband = local->hw.wiphy->bands[band];
- if (sband && !local->oper_channel) {
+ if (!sband)
+ continue;
+ if (!local->oper_channel) {
/* init channel we're on */
local->hw.conf.channel =
local->oper_channel =
local->scan_channel = &sband->channels[0];
}
- if (sband)
- channels += sband->n_channels;
+ channels += sband->n_channels;
+
+ if (max_bitrates < sband->n_bitrates)
+ max_bitrates = sband->n_bitrates;
+ supp_ht = supp_ht || sband->ht_cap.ht_supported;
}
local->int_scan_req.n_channels = channels;
@@ -859,6 +900,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+ /*
+ * Calculate scan IE length -- we need this to alloc
+ * memory and to subtract from the driver limit. It
+ * includes the (extended) supported rates and HT
+ * information -- SSID is the driver's responsibility.
+ */
+ local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */
+ if (supp_ht)
+ local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
+
+ if (!local->ops->hw_scan) {
+ /* For hw_scan, driver needs to set these up. */
+ local->hw.wiphy->max_scan_ssids = 4;
+ local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ }
+
+ /*
+ * If the driver supports any scan IEs, then assume the
+ * limit includes the IEs mac80211 will add, otherwise
+ * leave it at zero and let the driver sort it out; we
+ * still pass our IEs to the driver but userspace will
+ * not be allowed to in that case.
+ */
+ if (local->hw.wiphy->max_scan_ie_len)
+ local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
+
+ local->hw.wiphy->cipher_suites = cipher_suites;
+ local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
+ local->hw.wiphy->n_cipher_suites--;
+
result = wiphy_register(local->hw.wiphy);
if (result < 0)
goto fail_wiphy_register;
@@ -965,25 +1037,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}
+ local->network_latency_notifier.notifier_call =
+ ieee80211_max_network_latency;
+ result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
+ &local->network_latency_notifier);
+
+ if (result) {
+ rtnl_lock();
+ goto fail_pm_qos;
+ }
+
return 0;
-fail_wep:
+ fail_pm_qos:
+ ieee80211_led_exit(local);
+ ieee80211_remove_interfaces(local);
+ fail_wep:
rate_control_deinitialize(local);
-fail_rate:
+ fail_rate:
unregister_netdevice(local->mdev);
local->mdev = NULL;
-fail_dev:
+ fail_dev:
rtnl_unlock();
sta_info_stop(local);
-fail_sta_info:
+ fail_sta_info:
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
-fail_workqueue:
+ fail_workqueue:
if (local->mdev)
free_netdev(local->mdev);
-fail_mdev_alloc:
+ fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
-fail_wiphy_register:
+ fail_wiphy_register:
kfree(local->int_scan_req.channels);
return result;
}
@@ -996,6 +1081,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
+ pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
+ &local->network_latency_notifier);
+
rtnl_lock();
/*
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 132938b073d..3610c11286b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -17,6 +17,8 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
+#include <linux/pm_qos_params.h>
+#include <linux/crc32.h>
#include <net/mac80211.h>
#include <asm/unaligned.h>
@@ -80,6 +82,89 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
return count;
}
+/*
+ * ieee80211_enable_ht should be called only after the operating band
+ * has been determined as ht configuration depends on the hw's
+ * HT abilities for a specific band.
+ */
+static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_ht_info *hti,
+ u16 ap_ht_cap_flags)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_bss_ht_conf ht;
+ struct sta_info *sta;
+ u32 changed = 0;
+ bool enable_ht = true, ht_changed;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ memset(&ht, 0, sizeof(ht));
+
+ /* HT is not supported */
+ if (!sband->ht_cap.ht_supported)
+ enable_ht = false;
+
+ /* check that channel matches the right operating channel */
+ if (local->hw.conf.channel->center_freq !=
+ ieee80211_channel_to_frequency(hti->control_chan))
+ enable_ht = false;
+
+ if (enable_ht) {
+ channel_type = NL80211_CHAN_HT20;
+
+ if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
+ (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
+ switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ channel_type = NL80211_CHAN_HT40PLUS;
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ channel_type = NL80211_CHAN_HT40MINUS;
+ break;
+ }
+ }
+ }
+
+ ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
+ channel_type != local->hw.conf.channel_type;
+
+ local->oper_channel_type = channel_type;
+
+ if (ht_changed) {
+ /* channel_type change automatically detected */
+ ieee80211_hw_config(local, 0);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ifmgd->bssid);
+ if (sta)
+ rate_control_rate_update(local, sband, sta,
+ IEEE80211_RC_HT_CHANGED);
+
+ rcu_read_unlock();
+
+ }
+
+ /* disable HT */
+ if (!enable_ht)
+ return 0;
+
+ ht.operation_mode = le16_to_cpu(hti->operation_mode);
+
+ /* if bss configuration changed store the new one */
+ if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
+ changed |= BSS_CHANGED_HT;
+ sdata->vif.bss_conf.ht = ht;
+ }
+
+ return changed;
+}
+
/* frame sending functions */
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
@@ -325,6 +410,10 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
/* u.deauth.reason_code == u.disassoc.reason_code */
mgmt->u.deauth.reason_code = cpu_to_le16(reason);
+ if (stype == IEEE80211_STYPE_DEAUTH)
+ cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len);
+ else
+ cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len);
ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
}
@@ -359,6 +448,166 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
ieee80211_tx_skb(sdata, skb, 0);
}
+void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ __le16 fc;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS);
+ if (powersave)
+ fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+ nullfunc->frame_control = fc;
+ memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
+
+ ieee80211_tx_skb(sdata, skb, 0);
+}
+
+/* powersave */
+static void ieee80211_enable_ps(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ if (conf->dynamic_ps_timeout > 0 &&
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(conf->dynamic_ps_timeout));
+ } else {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ conf->flags |= IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ }
+}
+
+static void ieee80211_change_ps(struct ieee80211_local *local)
+{
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ if (local->ps_sdata) {
+ if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
+ return;
+
+ ieee80211_enable_ps(local, local->ps_sdata);
+ } else if (conf->flags & IEEE80211_CONF_PS) {
+ conf->flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ del_timer_sync(&local->dynamic_ps_timer);
+ cancel_work_sync(&local->dynamic_ps_enable_work);
+ }
+}
+
+/* need to hold RTNL or interface lock */
+void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
+{
+ struct ieee80211_sub_if_data *sdata, *found = NULL;
+ int count = 0;
+
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
+ local->ps_sdata = NULL;
+ return;
+ }
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!netif_running(sdata->dev))
+ continue;
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ continue;
+ found = sdata;
+ count++;
+ }
+
+ if (count == 1 && found->u.mgd.powersave) {
+ s32 beaconint_us;
+
+ if (latency < 0)
+ latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY);
+
+ beaconint_us = ieee80211_tu_to_usec(
+ found->vif.bss_conf.beacon_int);
+
+ if (beaconint_us > latency) {
+ local->ps_sdata = NULL;
+ } else {
+ u8 dtimper = found->vif.bss_conf.dtim_period;
+ int maxslp = 1;
+
+ if (dtimper > 1)
+ maxslp = min_t(int, dtimper,
+ latency / beaconint_us);
+
+ local->hw.conf.max_sleep_interval = maxslp;
+ local->ps_sdata = found;
+ }
+ } else {
+ local->ps_sdata = NULL;
+ }
+
+ ieee80211_change_ps(local);
+}
+
+void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local,
+ dynamic_ps_disable_work);
+
+ if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+ local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ }
+
+ ieee80211_wake_queues_by_reason(&local->hw,
+ IEEE80211_QUEUE_STOP_REASON_PS);
+}
+
+void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local,
+ dynamic_ps_enable_work);
+ struct ieee80211_sub_if_data *sdata = local->ps_sdata;
+
+ /* can only happen when PS was just disabled anyway */
+ if (!sdata)
+ return;
+
+ if (local->hw.conf.flags & IEEE80211_CONF_PS)
+ return;
+
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 1);
+
+ local->hw.conf.flags |= IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+}
+
+void ieee80211_dynamic_ps_timer(unsigned long data)
+{
+ struct ieee80211_local *local = (void *) data;
+
+ queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
+}
+
/* MLME */
static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
struct ieee80211_if_managed *ifmgd,
@@ -435,30 +684,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
}
}
-static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid)
-{
- u8 mask;
- u8 index, indexn1, indexn2;
- struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim;
-
- if (unlikely(!tim || elems->tim_len < 4))
- return false;
-
- aid &= 0x3fff;
- index = aid / 8;
- mask = 1 << (aid & 7);
-
- indexn1 = tim->bitmap_ctrl & 0xfe;
- indexn2 = elems->tim_len + indexn1 - 4;
-
- if (index < indexn1 || index > indexn2)
- return false;
-
- index -= indexn1;
-
- return !!(tim->virtual_map[index] & mask);
-}
-
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
u16 capab, bool erp_valid, u8 erp)
{
@@ -634,18 +859,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_info_changed |= BSS_CHANGED_BASIC_RATES;
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
- if (local->powersave) {
- if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
- local->hw.conf.dynamic_ps_timeout > 0) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(
- local->hw.conf.dynamic_ps_timeout));
- } else {
- if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
- ieee80211_send_nullfunc(local, sdata, 1);
- conf->flags |= IEEE80211_CONF_PS;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- }
+ /* will be same as sdata */
+ if (local->ps_sdata) {
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
}
netif_tx_start_all_queues(sdata->dev);
@@ -714,7 +932,7 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
" timed out\n",
sdata->dev->name, ifmgd->bssid);
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_sta_send_apinfo(sdata);
+ cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
sdata->local->hw.conf.channel->center_freq,
ifmgd->ssid, ifmgd->ssid_len);
@@ -897,7 +1115,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
" timed out\n",
sdata->dev->name, ifmgd->bssid);
ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_sta_send_apinfo(sdata);
+ cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid);
ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
sdata->local->hw.conf.channel->center_freq,
ifmgd->ssid, ifmgd->ssid_len);
@@ -1187,7 +1405,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, true, false, 0);
ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
- cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len);
+ cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len);
}
@@ -1218,7 +1436,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
}
ieee80211_set_disassoc(sdata, false, false, reason_code);
- cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len);
+ cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len);
}
@@ -1287,6 +1505,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
* association next time. This works around some broken APs
* which do not correctly reject reassociation requests. */
ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+ cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
+ if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
+ /* Wait for SME to decide what to do next */
+ ifmgd->state = IEEE80211_STA_MLME_DISABLED;
+ }
return;
}
@@ -1518,46 +1741,74 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
}
+/*
+ * This is the canonical list of information elements we care about,
+ * the filter code also gives us all changes to the Microsoft OUI
+ * (00:50:F2) vendor IE which is used for WMM which we need to track.
+ *
+ * We implement beacon filtering in software since that means we can
+ * avoid processing the frame here and in cfg80211, and userspace
+ * will not be able to tell whether the hardware supports it or not.
+ *
+ * XXX: This list needs to be dynamic -- userspace needs to be able to
+ * add items it requires. It also needs to be able to tell us to
+ * look out for other vendor IEs.
+ */
+static const u64 care_about_ies =
+ (1ULL << WLAN_EID_COUNTRY) |
+ (1ULL << WLAN_EID_ERP_INFO) |
+ (1ULL << WLAN_EID_CHANNEL_SWITCH) |
+ (1ULL << WLAN_EID_PWR_CONSTRAINT) |
+ (1ULL << WLAN_EID_HT_CAPABILITY) |
+ (1ULL << WLAN_EID_HT_INFORMATION);
+
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status)
{
- struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
size_t baselen;
struct ieee802_11_elems elems;
struct ieee80211_local *local = sdata->local;
u32 changed = 0;
- bool erp_valid, directed_tim;
+ bool erp_valid, directed_tim = false;
u8 erp_value = 0;
+ u32 ncrc;
/* Process beacon from the current BSS */
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
if (baselen > len)
return;
- ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ if (rx_status->freq != local->hw.conf.channel->center_freq)
return;
- ifmgd = &sdata->u.mgd;
-
if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
- if (rx_status->freq != local->hw.conf.channel->center_freq)
+ ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
+ ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
+ len - baselen, &elems,
+ care_about_ies, ncrc);
+
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
+ ifmgd->aid);
+
+ ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim));
+
+ if (ncrc == ifmgd->beacon_crc)
return;
+ ifmgd->beacon_crc = ncrc;
+
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
elems.wmm_param_len);
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
- directed_tim = ieee80211_check_tim(&elems, ifmgd->aid);
-
if (directed_tim) {
if (local->hw.conf.dynamic_ps_timeout > 0) {
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
@@ -1930,6 +2181,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd;
+ u32 hw_flags;
ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->work, ieee80211_sta_work);
@@ -1949,6 +2201,13 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
IEEE80211_STA_AUTO_CHANNEL_SEL;
if (sdata->local->hw.queues >= 4)
ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
+
+ hw_flags = sdata->local->hw.flags;
+
+ if (hw_flags & IEEE80211_HW_SUPPORTS_PS) {
+ ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE;
+ sdata->local->hw.conf.dynamic_ps_timeout = 500;
+ }
}
/* configuration hooks */
@@ -2068,9 +2327,6 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason
printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
sdata->dev->name, reason);
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return -EINVAL;
-
ieee80211_set_disassoc(sdata, true, true, reason);
return 0;
}
@@ -2082,9 +2338,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
sdata->dev->name, reason);
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return -EINVAL;
-
if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))
return -ENOLINK;
@@ -2104,75 +2357,17 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
rcu_read_unlock();
}
-void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
+int ieee80211_max_network_latency(struct notifier_block *nb,
+ unsigned long data, void *dummy)
{
+ s32 latency_usec = (s32) data;
struct ieee80211_local *local =
- container_of(work, struct ieee80211_local,
- dynamic_ps_disable_work);
+ container_of(nb, struct ieee80211_local,
+ network_latency_notifier);
- if (local->hw.conf.flags & IEEE80211_CONF_PS) {
- local->hw.conf.flags &= ~IEEE80211_CONF_PS;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- }
-
- ieee80211_wake_queues_by_reason(&local->hw,
- IEEE80211_QUEUE_STOP_REASON_PS);
-}
-
-void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
-{
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local,
- dynamic_ps_enable_work);
- /* XXX: using scan_sdata is completely broken! */
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-
- if (local->hw.conf.flags & IEEE80211_CONF_PS)
- return;
-
- if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && sdata)
- ieee80211_send_nullfunc(local, sdata, 1);
-
- local->hw.conf.flags |= IEEE80211_CONF_PS;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-}
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, latency_usec);
+ mutex_unlock(&local->iflist_mtx);
-void ieee80211_dynamic_ps_timer(unsigned long data)
-{
- struct ieee80211_local *local = (void *) data;
-
- queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
-}
-
-void ieee80211_send_nullfunc(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- int powersave)
-{
- struct sk_buff *skb;
- struct ieee80211_hdr *nullfunc;
- __le16 fc;
-
- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
- return;
-
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
- "frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
- memset(nullfunc, 0, 24);
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
- IEEE80211_FCTL_TODS);
- if (powersave)
- fc |= cpu_to_le16(IEEE80211_FCTL_PM);
- nullfunc->frame_control = fc;
- memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
- memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
-
- ieee80211_tx_skb(sdata, skb, 0);
+ return 0;
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 81985d27cbd..b38986c9dee 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -72,119 +72,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
return 0;
}
-int __ieee80211_resume(struct ieee80211_hw *hw)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_if_init_conf conf;
- struct sta_info *sta;
- unsigned long flags;
- int res;
-
- /* restart hardware */
- if (local->open_count) {
- res = local->ops->start(hw);
-
- ieee80211_led_radio(local, hw->conf.radio_enabled);
- }
-
- /* add interfaces */
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
- netif_running(sdata->dev)) {
- conf.vif = &sdata->vif;
- conf.type = sdata->vif.type;
- conf.mac_addr = sdata->dev->dev_addr;
- res = local->ops->add_interface(hw, &conf);
- }
- }
-
- /* add STAs back */
- if (local->ops->sta_notify) {
- spin_lock_irqsave(&local->sta_lock, flags);
- list_for_each_entry(sta, &local->sta_list, list) {
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
-
- local->ops->sta_notify(hw, &sdata->vif,
- STA_NOTIFY_ADD, &sta->sta);
- }
- spin_unlock_irqrestore(&local->sta_lock, flags);
- }
-
- /* Clear Suspend state so that ADDBA requests can be processed */
-
- rcu_read_lock();
-
- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
- clear_sta_flags(sta, WLAN_STA_SUSPEND);
- }
- }
-
- rcu_read_unlock();
-
- /* add back keys */
- list_for_each_entry(sdata, &local->interfaces, list)
- if (netif_running(sdata->dev))
- ieee80211_enable_keys(sdata);
-
- /* setup RTS threshold */
- if (local->ops->set_rts_threshold)
- local->ops->set_rts_threshold(hw, local->rts_threshold);
-
- /* reconfigure hardware */
- ieee80211_hw_config(local, ~0);
-
- netif_addr_lock_bh(local->mdev);
- ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
-
- /* Finally also reconfigure all the BSS information */
- list_for_each_entry(sdata, &local->interfaces, list) {
- u32 changed = ~0;
- if (!netif_running(sdata->dev))
- continue;
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_STATION:
- /* disable beacon change bits */
- changed &= ~IEEE80211_IFCC_BEACON;
- /* fall through */
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- /*
- * Driver's config_interface can fail if rfkill is
- * enabled. Accommodate this return code.
- * FIXME: When mac80211 has knowledge of rfkill
- * state the code below can change back to:
- * WARN(ieee80211_if_config(sdata, changed));
- * ieee80211_bss_info_change_notify(sdata, ~0);
- */
- if (ieee80211_if_config(sdata, changed))
- printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
- sdata->dev->name);
- else
- ieee80211_bss_info_change_notify(sdata, ~0);
- break;
- case NL80211_IFTYPE_WDS:
- break;
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_MONITOR:
- /* ignore virtual */
- break;
- case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
- WARN_ON(1);
- break;
- }
- }
-
- ieee80211_wake_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
-
- return 0;
-}
+/*
+ * __ieee80211_resume() is a static inline which just calls
+ * ieee80211_reconfig(), which is also needed for hardware
+ * hang/firmware failure/etc. recovery.
+ */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9776f73c51a..a5afb79dab6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1932,7 +1932,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
!ieee80211_is_auth(hdr->frame_control))
goto ignore;
- mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr);
+ mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL);
ignore:
dev_kfree_skb(rx->skb);
rx->skb = NULL;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 3bf9839f591..f25b07feabf 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -253,7 +253,7 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
- if (!local->powersave)
+ if (!local->ps_sdata)
ieee80211_send_nullfunc(local, sdata, 0);
else {
/*
@@ -285,12 +285,16 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (WARN_ON(!local->scan_req))
return;
+ if (local->hw_scanning) {
+ kfree(local->scan_req->ie);
+ local->scan_req->ie = local->orig_ies;
+ local->scan_req->ie_len = local->orig_ies_len;
+ }
+
if (local->scan_req != &local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL;
- local->last_scan_completed = jiffies;
-
if (local->hw_scanning) {
local->hw_scanning = false;
/*
@@ -457,12 +461,28 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
}
if (local->ops->hw_scan) {
- int rc;
+ u8 *ies;
+ int rc, ielen;
+
+ ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
+ local->scan_ies_len + req->ie_len, GFP_KERNEL);
+ if (!ies)
+ return -ENOMEM;
+
+ ielen = ieee80211_build_preq_ies(local, ies,
+ req->ie, req->ie_len);
+ local->orig_ies = req->ie;
+ local->orig_ies_len = req->ie_len;
+ req->ie = ies;
+ req->ie_len = ielen;
local->hw_scanning = true;
rc = local->ops->hw_scan(local_to_hw(local), req);
if (rc) {
local->hw_scanning = false;
+ kfree(ies);
+ req->ie_len = local->orig_ies_len;
+ req->ie = local->orig_ies;
return rc;
}
local->scan_sdata = scan_sdata;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 5f7a2624ed7..48bf78e7fa7 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -15,7 +15,7 @@
*/
#include <linux/ieee80211.h>
-#include <net/wireless.h>
+#include <net/cfg80211.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "sta_info.h"
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c5f14e6bbde..654a8e963cc 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -686,41 +686,10 @@ static void sta_info_debugfs_add_work(struct work_struct *work)
}
#endif
-static void __ieee80211_run_pending_flush(struct ieee80211_local *local)
-{
- struct sta_info *sta;
- unsigned long flags;
-
- ASSERT_RTNL();
-
- spin_lock_irqsave(&local->sta_lock, flags);
- while (!list_empty(&local->sta_flush_list)) {
- sta = list_first_entry(&local->sta_flush_list,
- struct sta_info, list);
- list_del(&sta->list);
- spin_unlock_irqrestore(&local->sta_lock, flags);
- sta_info_destroy(sta);
- spin_lock_irqsave(&local->sta_lock, flags);
- }
- spin_unlock_irqrestore(&local->sta_lock, flags);
-}
-
-static void ieee80211_sta_flush_work(struct work_struct *work)
-{
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local, sta_flush_work);
-
- rtnl_lock();
- __ieee80211_run_pending_flush(local);
- rtnl_unlock();
-}
-
void sta_info_init(struct ieee80211_local *local)
{
spin_lock_init(&local->sta_lock);
INIT_LIST_HEAD(&local->sta_list);
- INIT_LIST_HEAD(&local->sta_flush_list);
- INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work);
setup_timer(&local->sta_cleanup, sta_info_cleanup,
(unsigned long)local);
@@ -741,7 +710,6 @@ int sta_info_start(struct ieee80211_local *local)
void sta_info_stop(struct ieee80211_local *local)
{
del_timer(&local->sta_cleanup);
- cancel_work_sync(&local->sta_flush_work);
#ifdef CONFIG_MAC80211_DEBUGFS
/*
* Make sure the debugfs adding work isn't pending after this
@@ -752,10 +720,7 @@ void sta_info_stop(struct ieee80211_local *local)
cancel_work_sync(&local->sta_debugfs_add);
#endif
- rtnl_lock();
sta_info_flush(local, NULL);
- __ieee80211_run_pending_flush(local);
- rtnl_unlock();
}
/**
@@ -767,7 +732,7 @@ void sta_info_stop(struct ieee80211_local *local)
* @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
*/
int sta_info_flush(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
+ struct ieee80211_sub_if_data *sdata)
{
struct sta_info *sta, *tmp;
LIST_HEAD(tmp_list);
@@ -775,7 +740,6 @@ int sta_info_flush(struct ieee80211_local *local,
unsigned long flags;
might_sleep();
- ASSERT_RTNL();
spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
@@ -795,39 +759,6 @@ int sta_info_flush(struct ieee80211_local *local,
return ret;
}
-/**
- * sta_info_flush_delayed - flush matching STA entries from the STA table
- *
- * This function unlinks all stations for a given interface and queues
- * them for freeing. Note that the workqueue function scheduled here has
- * to run before any new keys can be added to the system to avoid set_key()
- * callback ordering issues.
- *
- * @sdata: the interface
- */
-void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta, *tmp;
- unsigned long flags;
- bool work = false;
-
- spin_lock_irqsave(&local->sta_lock, flags);
- list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
- if (sdata == sta->sdata) {
- __sta_info_unlink(&sta);
- if (sta) {
- list_add_tail(&sta->list,
- &local->sta_flush_list);
- work = true;
- }
- }
- }
- if (work)
- schedule_work(&local->sta_flush_work);
- spin_unlock_irqrestore(&local->sta_lock, flags);
-}
-
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time)
{
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 5534d489f50..31a8990ce40 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -442,8 +442,7 @@ void sta_info_init(struct ieee80211_local *local);
int sta_info_start(struct ieee80211_local *local);
void sta_info_stop(struct ieee80211_local *local);
int sta_info_flush(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata);
-void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
+ struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3fb04a86444..1865622003c 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -409,8 +409,24 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr);
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- clear_sta_flags(sta, WLAN_STA_PSPOLL);
+ if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
+ /*
+ * The sleeping station with pending data is now snoozing.
+ * It queried us for its buffered frames and will go back
+ * to deep sleep once it got everything.
+ *
+ * inform the driver, in case the hardware does powersave
+ * frame filtering and keeps a station blacklist on its own
+ * (e.g: p54), so that frames can be delivered unimpeded.
+ *
+ * Note: It should be save to disable the filter now.
+ * As, it is really unlikely that we still have any pending
+ * frame for this station in the hw's buffers/fifos left,
+ * that is not rejected with a unsuccessful tx_status yet.
+ */
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ }
return TX_CONTINUE;
}
@@ -429,7 +445,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
- struct ieee80211_key *key;
+ struct ieee80211_key *key = NULL;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@@ -500,7 +516,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
sband = tx->local->hw.wiphy->bands[tx->channel->band];
len = min_t(int, tx->skb->len + FCS_LEN,
- tx->local->fragmentation_threshold);
+ tx->local->hw.wiphy->frag_threshold);
/* set up the tx rate control struct we give the RC algo */
txrc.hw = local_to_hw(tx->local);
@@ -511,8 +527,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
/* set up RTS protection if desired */
- if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
- len > tx->local->rts_threshold) {
+ if (len > tx->local->hw.wiphy->rts_threshold) {
txrc.rts = rts = true;
}
@@ -754,7 +769,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
struct sk_buff *skb = tx->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
- int frag_threshold = tx->local->fragmentation_threshold;
+ int frag_threshold = tx->local->hw.wiphy->frag_threshold;
int hdrlen;
int fragnum;
@@ -1072,7 +1087,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
if (tx->flags & IEEE80211_TX_FRAGMENTED) {
if ((tx->flags & IEEE80211_TX_UNICAST) &&
- skb->len + FCS_LEN > local->fragmentation_threshold &&
+ skb->len + FCS_LEN > local->hw.wiphy->frag_threshold &&
!(info->flags & IEEE80211_TX_CTL_AMPDU))
tx->flags |= IEEE80211_TX_FRAGMENTED;
else
@@ -2086,18 +2101,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_hdr *hdr;
+ struct sk_buff *presp = rcu_dereference(ifibss->presp);
- if (!ifibss->probe_resp)
+ if (!presp)
goto out;
- skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC);
+ skb = skb_copy(presp, GFP_ATOMIC);
if (!skb)
goto out;
hdr = (struct ieee80211_hdr *) skb->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON);
-
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211_mgmt *mgmt;
u8 *pos;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index fdf432f1455..61876eb50b4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -20,6 +20,7 @@
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/bitmap.h>
+#include <linux/crc32.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
@@ -28,6 +29,7 @@
#include "rate.h"
#include "mesh.h"
#include "wme.h"
+#include "led.h"
/* privid for wiphys to determine whether they belong to us or not */
void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -536,8 +538,16 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems)
{
+ ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
+}
+
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ u64 filter, u32 crc)
+{
size_t left = len;
u8 *pos = start;
+ bool calc_crc = filter != 0;
memset(elems, 0, sizeof(*elems));
elems->ie_start = start;
@@ -551,7 +561,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
left -= 2;
if (elen > left)
- return;
+ break;
+
+ if (calc_crc && id < 64 && (filter & BIT(id)))
+ crc = crc32_be(crc, pos - 2, elen + 2);
switch (id) {
case WLAN_EID_SSID:
@@ -575,8 +588,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
elems->cf_params_len = elen;
break;
case WLAN_EID_TIM:
- elems->tim = pos;
- elems->tim_len = elen;
+ if (elen >= sizeof(struct ieee80211_tim_ie)) {
+ elems->tim = (void *)pos;
+ elems->tim_len = elen;
+ }
break;
case WLAN_EID_IBSS_PARAMS:
elems->ibss_params = pos;
@@ -586,15 +601,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
elems->challenge = pos;
elems->challenge_len = elen;
break;
- case WLAN_EID_WPA:
+ case WLAN_EID_VENDOR_SPECIFIC:
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
pos[2] == 0xf2) {
/* Microsoft OUI (00:50:F2) */
+
+ if (calc_crc)
+ crc = crc32_be(crc, pos - 2, elen + 2);
+
if (pos[3] == 1) {
/* OUI Type 1 - WPA IE */
elems->wpa = pos;
elems->wpa_len = elen;
} else if (elen >= 5 && pos[3] == 2) {
+ /* OUI Type 2 - WMM IE */
if (pos[4] == 0) {
elems->wmm_info = pos;
elems->wmm_info_len = elen;
@@ -679,6 +699,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
left -= elen;
pos += elen;
}
+
+ return crc;
}
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
@@ -831,16 +853,73 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb, encrypt);
}
+int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
+ const u8 *ie, size_t ie_len)
+{
+ struct ieee80211_supported_band *sband;
+ u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
+ int i;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ pos = buffer;
+
+ *pos++ = WLAN_EID_SUPP_RATES;
+ supp_rates_len = pos;
+ *pos++ = 0;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *rate = &sband->bitrates[i];
+
+ if (esupp_rates_len) {
+ *esupp_rates_len += 1;
+ } else if (*supp_rates_len == 8) {
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ esupp_rates_len = pos;
+ *pos++ = 1;
+ } else
+ *supp_rates_len += 1;
+
+ *pos++ = rate->bitrate / 5;
+ }
+
+ if (sband->ht_cap.ht_supported) {
+ __le16 tmp = cpu_to_le16(sband->ht_cap.cap);
+
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+ memcpy(pos, &tmp, sizeof(u16));
+ pos += sizeof(u16);
+ /* TODO: needs a define here for << 2 */
+ *pos++ = sband->ht_cap.ampdu_factor |
+ (sband->ht_cap.ampdu_density << 2);
+ memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+ pos += sizeof(sband->ht_cap.mcs);
+ pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
+ }
+
+ /*
+ * If adding more here, adjust code in main.c
+ * that calculates local->scan_ies_len.
+ */
+
+ if (ie) {
+ memcpy(pos, ie, ie_len);
+ pos += ie_len;
+ }
+
+ return pos - buffer;
+}
+
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
- u8 *ssid, size_t ssid_len,
- u8 *ie, size_t ie_len)
+ const u8 *ssid, size_t ssid_len,
+ const u8 *ie, size_t ie_len)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
- u8 *pos, *supp_rates, *esupp_rates = NULL;
- int i;
+ u8 *pos;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
ie_len);
@@ -867,31 +946,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
- supp_rates = skb_put(skb, 2);
- supp_rates[0] = WLAN_EID_SUPP_RATES;
- supp_rates[1] = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- for (i = 0; i < sband->n_bitrates; i++) {
- struct ieee80211_rate *rate = &sband->bitrates[i];
- if (esupp_rates) {
- pos = skb_put(skb, 1);
- esupp_rates[1]++;
- } else if (supp_rates[1] == 8) {
- esupp_rates = skb_put(skb, 3);
- esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
- esupp_rates[1] = 1;
- pos = &esupp_rates[2];
- } else {
- pos = skb_put(skb, 1);
- supp_rates[1]++;
- }
- *pos = rate->bitrate / 5;
- }
-
- if (ie)
- memcpy(skb_put(skb, ie_len), ie, ie_len);
+ skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len));
ieee80211_tx_skb(sdata, skb, 0);
}
@@ -931,3 +988,120 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
}
return supp_rates;
}
+
+int ieee80211_reconfig(struct ieee80211_local *local)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_init_conf conf;
+ struct sta_info *sta;
+ unsigned long flags;
+ int res;
+
+ /* restart hardware */
+ if (local->open_count) {
+ res = local->ops->start(hw);
+
+ ieee80211_led_radio(local, hw->conf.radio_enabled);
+ }
+
+ /* add interfaces */
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ netif_running(sdata->dev)) {
+ conf.vif = &sdata->vif;
+ conf.type = sdata->vif.type;
+ conf.mac_addr = sdata->dev->dev_addr;
+ res = local->ops->add_interface(hw, &conf);
+ }
+ }
+
+ /* add STAs back */
+ if (local->ops->sta_notify) {
+ spin_lock_irqsave(&local->sta_lock, flags);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
+
+ local->ops->sta_notify(hw, &sdata->vif,
+ STA_NOTIFY_ADD, &sta->sta);
+ }
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+ }
+
+ /* Clear Suspend state so that ADDBA requests can be processed */
+
+ rcu_read_lock();
+
+ if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ clear_sta_flags(sta, WLAN_STA_SUSPEND);
+ }
+ }
+
+ rcu_read_unlock();
+
+ /* setup RTS threshold */
+ if (local->ops->set_rts_threshold)
+ local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold);
+
+ /* reconfigure hardware */
+ ieee80211_hw_config(local, ~0);
+
+ netif_addr_lock_bh(local->mdev);
+ ieee80211_configure_filter(local);
+ netif_addr_unlock_bh(local->mdev);
+
+ /* Finally also reconfigure all the BSS information */
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ u32 changed = ~0;
+ if (!netif_running(sdata->dev))
+ continue;
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ /* disable beacon change bits */
+ changed &= ~IEEE80211_IFCC_BEACON;
+ /* fall through */
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ /*
+ * Driver's config_interface can fail if rfkill is
+ * enabled. Accommodate this return code.
+ * FIXME: When mac80211 has knowledge of rfkill
+ * state the code below can change back to:
+ * WARN(ieee80211_if_config(sdata, changed));
+ * ieee80211_bss_info_change_notify(sdata, ~0);
+ */
+ if (ieee80211_if_config(sdata, changed))
+ printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
+ sdata->dev->name);
+ else
+ ieee80211_bss_info_change_notify(sdata, ~0);
+ break;
+ case NL80211_IFTYPE_WDS:
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_MONITOR:
+ /* ignore virtual */
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
+ WARN_ON(1);
+ break;
+ }
+ }
+
+ /* add back keys */
+ list_for_each_entry(sdata, &local->interfaces, list)
+ if (netif_running(sdata->dev))
+ ieee80211_enable_keys(sdata);
+
+ ieee80211_wake_queues_by_reason(hw,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+
+ return 0;
+}
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 959aa8379cc..1a649da42c4 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -149,17 +149,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL;
+ return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.mgd.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->vif.type == NL80211_IFTYPE_ADHOC)
- sdata->u.ibss.flags |=
- IEEE80211_IBSS_AUTO_CHANNEL_SEL;
- else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.mgd.flags |=
IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
@@ -183,6 +180,10 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
struct iw_freq *freq, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
freq->m = local->hw.conf.channel->center_freq;
freq->e = 6;
@@ -195,15 +196,17 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
size_t len = data->length;
int ret;
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+
/* iwconfig uses nul termination in SSID.. */
if (len > 0 && ssid[len - 1] == '\0')
len--;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (data->flags)
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
@@ -217,8 +220,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
ieee80211_sta_req_auth(sdata);
return 0;
- } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return ieee80211_ibss_set_ssid(sdata, ssid, len);
+ }
return -EOPNOTSUPP;
}
@@ -229,9 +231,13 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
size_t len;
-
struct ieee80211_sub_if_data *sdata;
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
if (res == 0) {
@@ -240,14 +246,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
} else
data->flags = 0;
return res;
- } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- int res = ieee80211_ibss_get_ssid(sdata, ssid, &len);
- if (res == 0) {
- data->length = len;
- data->flags = 1;
- } else
- data->flags = 0;
- return res;
}
return -EOPNOTSUPP;
@@ -258,9 +256,11 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
int ret;
@@ -277,16 +277,6 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
ieee80211_sta_req_auth(sdata);
return 0;
- } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
- sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |
- IEEE80211_IBSS_AUTO_CHANNEL_SEL;
- else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
- sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL;
- else
- sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL;
-
- return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
/*
* If it is necessary to update the WDS peer address
@@ -312,9 +302,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
ap_addr->sa_family = ARPHRD_ETHER;
@@ -322,13 +314,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
} else
memset(&ap_addr->sa_data, 0, ETH_ALEN);
return 0;
- } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- return 0;
} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
ap_addr->sa_family = ARPHRD_ETHER;
memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
@@ -487,155 +472,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
return 0;
}
-static int ieee80211_ioctl_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- if (rts->disabled)
- local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
- else if (!rts->fixed)
- /* if the rts value is not fixed, then take default */
- local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
- else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
- return -EINVAL;
- else
- local->rts_threshold = rts->value;
-
- /* If the wlan card performs RTS/CTS in hardware/firmware,
- * configure it here */
-
- if (local->ops->set_rts_threshold)
- local->ops->set_rts_threshold(local_to_hw(local),
- local->rts_threshold);
-
- return 0;
-}
-
-static int ieee80211_ioctl_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- rts->value = local->rts_threshold;
- rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
- rts->fixed = 1;
-
- return 0;
-}
-
-
-static int ieee80211_ioctl_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- if (frag->disabled)
- local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
- else if (!frag->fixed)
- local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
- else if (frag->value < 256 ||
- frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
- return -EINVAL;
- else {
- /* Fragment length must be even, so strip LSB. */
- local->fragmentation_threshold = frag->value & ~0x1;
- }
-
- return 0;
-}
-
-static int ieee80211_ioctl_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- frag->value = local->fragmentation_threshold;
- frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD);
- frag->fixed = 1;
-
- return 0;
-}
-
-
-static int ieee80211_ioctl_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- if (retry->disabled ||
- (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
- return -EINVAL;
-
- if (retry->flags & IW_RETRY_MAX) {
- local->hw.conf.long_frame_max_tx_count = retry->value;
- } else if (retry->flags & IW_RETRY_MIN) {
- local->hw.conf.short_frame_max_tx_count = retry->value;
- } else {
- local->hw.conf.long_frame_max_tx_count = retry->value;
- local->hw.conf.short_frame_max_tx_count = retry->value;
- }
-
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
-
- return 0;
-}
-
-
-static int ieee80211_ioctl_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- retry->disabled = 0;
- if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
- /* first return min value, iwconfig will ask max value
- * later if needed */
- retry->flags |= IW_RETRY_LIMIT;
- retry->value = local->hw.conf.short_frame_max_tx_count;
- if (local->hw.conf.long_frame_max_tx_count !=
- local->hw.conf.short_frame_max_tx_count)
- retry->flags |= IW_RETRY_MIN;
- return 0;
- }
- if (retry->flags & IW_RETRY_MAX) {
- retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
- retry->value = local->hw.conf.long_frame_max_tx_count;
- }
-
- return 0;
-}
-
-static int ieee80211_ioctl_siwmlme(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct ieee80211_sub_if_data *sdata;
- struct iw_mlme *mlme = (struct iw_mlme *) extra;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (!(sdata->vif.type == NL80211_IFTYPE_STATION))
- return -EINVAL;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* TODO: mlme->addr.sa_data */
- return ieee80211_sta_deauthenticate(sdata, mlme->reason_code);
- case IW_MLME_DISASSOC:
- /* TODO: mlme->addr.sa_data */
- return ieee80211_sta_disassociate(sdata, mlme->reason_code);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
static int ieee80211_ioctl_siwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *keybuf)
@@ -675,7 +511,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
!sdata->default_key,
keybuf, erq->length);
- if (!ret) {
+ if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) {
if (remove)
sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED;
else
@@ -747,7 +583,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_conf *conf = &local->hw.conf;
- int ret = 0, timeout = 0;
+ int timeout = 0;
bool ps;
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
@@ -779,42 +615,18 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
timeout = wrq->value / 1000;
set:
- if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
- return ret;
+ if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
+ return 0;
- local->powersave = ps;
+ sdata->u.mgd.powersave = ps;
conf->dynamic_ps_timeout = timeout;
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
- ret = ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
- return ret;
+ ieee80211_recalc_ps(local, -1);
- if (conf->dynamic_ps_timeout > 0 &&
- !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(conf->dynamic_ps_timeout));
- } else {
- if (local->powersave) {
- if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
- ieee80211_send_nullfunc(local, sdata, 1);
- conf->flags |= IEEE80211_CONF_PS;
- ret = ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
- } else {
- conf->flags &= ~IEEE80211_CONF_PS;
- ret = ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
- if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
- ieee80211_send_nullfunc(local, sdata, 0);
- del_timer_sync(&local->dynamic_ps_timer);
- cancel_work_sync(&local->dynamic_ps_enable_work);
- }
- }
-
- return ret;
+ return 0;
}
static int ieee80211_ioctl_giwpower(struct net_device *dev,
@@ -822,9 +634,9 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev,
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);
- wrqu->power.disabled = !local->powersave;
+ wrqu->power.disabled = !sdata->u.mgd.powersave;
return 0;
}
@@ -1099,7 +911,7 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) NULL, /* SIOCGIWTHRSPY */
(iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
(iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
- (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
+ (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
(iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
(iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
@@ -1111,14 +923,14 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) NULL, /* -- hole -- */
(iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
(iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
- (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
- (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
- (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
- (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
+ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
+ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
+ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
+ (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
(iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
- (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
- (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
+ (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
+ (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
(iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
(iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
(iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 4f8bfea278f..dcfae8884b8 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -122,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
- (void *) skb->data);
+ (void *) skb->data, NULL);
return RX_DROP_UNUSABLE;
}
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 84efde97c5a..60a34f3b5f6 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -47,12 +47,6 @@ enum rfkill_global_sched_op {
RFKILL_GLOBAL_OP_UNBLOCK,
};
-/*
- * Currently, the code marked with RFKILL_NEED_SWSET is inactive.
- * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the
- * future, when such events are added, that code will be necessary.
- */
-
struct rfkill_task {
struct delayed_work dwork;
@@ -65,14 +59,6 @@ struct rfkill_task {
/* pending regular switch operations (1=pending) */
unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-#ifdef RFKILL_NEED_SWSET
- /* set operation pending (1=pending) */
- unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
- /* desired state for pending set operation (1=unblock) */
- unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-#endif
-
/* should the state be complemented (1=yes) */
unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
@@ -111,24 +97,6 @@ static void __rfkill_handle_global_op(enum rfkill_global_sched_op op)
}
}
-#ifdef RFKILL_NEED_SWSET
-static void __rfkill_handle_normal_op(const enum rfkill_type type,
- const bool sp, const bool s, const bool c)
-{
- enum rfkill_state state;
-
- if (sp)
- state = (s) ? RFKILL_STATE_UNBLOCKED :
- RFKILL_STATE_SOFT_BLOCKED;
- else
- state = rfkill_get_global_state(type);
-
- if (c)
- state = rfkill_state_complement(state);
-
- rfkill_switch_all(type, state);
-}
-#else
static void __rfkill_handle_normal_op(const enum rfkill_type type,
const bool c)
{
@@ -140,7 +108,6 @@ static void __rfkill_handle_normal_op(const enum rfkill_type type,
rfkill_switch_all(type, state);
}
-#endif
static void rfkill_task_handler(struct work_struct *work)
{
@@ -171,21 +138,11 @@ static void rfkill_task_handler(struct work_struct *work)
i < RFKILL_TYPE_MAX) {
if (test_and_clear_bit(i, task->sw_pending)) {
bool c;
-#ifdef RFKILL_NEED_SWSET
- bool sp, s;
- sp = test_and_clear_bit(i,
- task->sw_setpending);
- s = test_bit(i, task->sw_newstate);
-#endif
c = test_and_clear_bit(i,
task->sw_togglestate);
spin_unlock_irq(&task->lock);
-#ifdef RFKILL_NEED_SWSET
- __rfkill_handle_normal_op(i, sp, s, c);
-#else
__rfkill_handle_normal_op(i, c);
-#endif
spin_lock_irq(&task->lock);
}
@@ -238,32 +195,6 @@ static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
spin_unlock_irqrestore(&rfkill_task.lock, flags);
}
-#ifdef RFKILL_NEED_SWSET
-/* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */
-
-static void rfkill_schedule_set(enum rfkill_type type,
- enum rfkill_state desired_state)
-{
- unsigned long flags;
-
- if (rfkill_is_epo_lock_active())
- return;
-
- spin_lock_irqsave(&rfkill_task.lock, flags);
- if (!rfkill_task.global_op_pending) {
- set_bit(type, rfkill_task.sw_pending);
- set_bit(type, rfkill_task.sw_setpending);
- clear_bit(type, rfkill_task.sw_togglestate);
- if (desired_state)
- set_bit(type, rfkill_task.sw_newstate);
- else
- clear_bit(type, rfkill_task.sw_newstate);
- rfkill_schedule_ratelimited();
- }
- spin_unlock_irqrestore(&rfkill_task.lock, flags);
-}
-#endif
-
static void rfkill_schedule_toggle(enum rfkill_type type)
{
unsigned long flags;
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 3eaa39403c1..e2d4510623f 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -96,6 +96,7 @@ static void update_rfkill_state(struct rfkill *rfkill)
}
mutex_unlock(&rfkill->mutex);
}
+ rfkill_led_trigger(rfkill, rfkill->state);
}
/**
@@ -136,8 +137,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
oldstate = rfkill->state;
if (rfkill->get_state && !force &&
- !rfkill->get_state(rfkill->data, &newstate))
+ !rfkill->get_state(rfkill->data, &newstate)) {
rfkill->state = newstate;
+ }
switch (state) {
case RFKILL_STATE_HARD_BLOCKED:
@@ -172,6 +174,7 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
if (force || rfkill->state != oldstate)
rfkill_uevent(rfkill);
+ rfkill_led_trigger(rfkill, rfkill->state);
return retval;
}
@@ -200,10 +203,11 @@ static void __rfkill_switch_all(const enum rfkill_type type,
rfkill_global_states[type].current_state = state;
list_for_each_entry(rfkill, &rfkill_list, node) {
- if ((!rfkill->user_claim) && (rfkill->type == type)) {
+ if (rfkill->type == type) {
mutex_lock(&rfkill->mutex);
rfkill_toggle_radio(rfkill, state, 0);
mutex_unlock(&rfkill->mutex);
+ rfkill_led_trigger(rfkill, rfkill->state);
}
}
}
@@ -256,6 +260,7 @@ void rfkill_epo(void)
RFKILL_STATE_SOFT_BLOCKED;
}
mutex_unlock(&rfkill_global_mutex);
+ rfkill_led_trigger(rfkill, rfkill->state);
}
EXPORT_SYMBOL_GPL(rfkill_epo);
@@ -358,6 +363,7 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
rfkill_uevent(rfkill);
mutex_unlock(&rfkill->mutex);
+ rfkill_led_trigger(rfkill, rfkill->state);
return 0;
}
@@ -447,53 +453,14 @@ static ssize_t rfkill_claim_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct rfkill *rfkill = to_rfkill(dev);
-
- return sprintf(buf, "%d\n", rfkill->user_claim);
+ return sprintf(buf, "%d\n", 0);
}
static ssize_t rfkill_claim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct rfkill *rfkill = to_rfkill(dev);
- unsigned long claim_tmp;
- bool claim;
- int error;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (rfkill->user_claim_unsupported)
- return -EOPNOTSUPP;
-
- error = strict_strtoul(buf, 0, &claim_tmp);
- if (error)
- return error;
- claim = !!claim_tmp;
-
- /*
- * Take the global lock to make sure the kernel is not in
- * the middle of rfkill_switch_all
- */
- error = mutex_lock_killable(&rfkill_global_mutex);
- if (error)
- return error;
-
- if (rfkill->user_claim != claim) {
- if (!claim && !rfkill_epo_lock_active) {
- mutex_lock(&rfkill->mutex);
- rfkill_toggle_radio(rfkill,
- rfkill_global_states[rfkill->type].current_state,
- 0);
- mutex_unlock(&rfkill->mutex);
- }
- rfkill->user_claim = claim;
- }
-
- mutex_unlock(&rfkill_global_mutex);
-
- return error ? error : count;
+ return -EOPNOTSUPP;
}
static struct device_attribute rfkill_dev_attrs[] = {
@@ -559,6 +526,7 @@ static int rfkill_resume(struct device *dev)
1);
mutex_unlock(&rfkill->mutex);
+ rfkill_led_trigger(rfkill, rfkill->state);
}
return 0;
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c
index 2b75aee0421..a3616e2ccb8 100644
--- a/net/wimax/op-rfkill.c
+++ b/net/wimax/op-rfkill.c
@@ -113,7 +113,7 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
if (state != wimax_dev->rf_hw) {
wimax_dev->rf_hw = state;
rfkill_state = state == WIMAX_RF_ON ?
- RFKILL_STATE_OFF : RFKILL_STATE_ON;
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
if (wimax_dev->rf_hw == WIMAX_RF_ON
&& wimax_dev->rf_sw == WIMAX_RF_ON)
wimax_state = WIMAX_ST_READY;
@@ -259,10 +259,10 @@ int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
switch (state) {
- case RFKILL_STATE_ON:
+ case RFKILL_STATE_SOFT_BLOCKED:
rf_state = WIMAX_RF_OFF;
break;
- case RFKILL_STATE_OFF:
+ case RFKILL_STATE_UNBLOCKED:
rf_state = WIMAX_RF_ON;
break;
default:
@@ -361,10 +361,9 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
wimax_dev->rfkill = rfkill;
rfkill->name = wimax_dev->name;
- rfkill->state = RFKILL_STATE_OFF;
+ rfkill->state = RFKILL_STATE_UNBLOCKED;
rfkill->data = wimax_dev;
rfkill->toggle_radio = wimax_rfkill_toggle_radio;
- rfkill->user_claim_unsupported = 1;
/* Initialize the input device for the hw key */
input_dev = input_allocate_device();
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 6d1e7b27b75..14ea01c4a10 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d1f556535f6..2006a4ee60e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -14,7 +14,6 @@
#include <linux/device.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
-#include <net/wireless.h>
#include "nl80211.h"
#include "core.h"
#include "sysfs.h"
@@ -274,6 +273,16 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
drv->wiphy.dev.class = &ieee80211_class;
drv->wiphy.dev.platform_data = drv;
+ /*
+ * Initialize wiphy parameters to IEEE 802.11 MIB default values.
+ * Fragmentation and RTS threshold are disabled by default with the
+ * special -1 value.
+ */
+ drv->wiphy.retry_short = 7;
+ drv->wiphy.retry_long = 4;
+ drv->wiphy.frag_threshold = (u32) -1;
+ drv->wiphy.rts_threshold = (u32) -1;
+
return &drv->wiphy;
}
EXPORT_SYMBOL(wiphy_new);
@@ -450,6 +459,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
dev->ieee80211_ptr->netdev = dev;
mutex_unlock(&rdev->devlist_mtx);
break;
+ case NETDEV_GOING_DOWN:
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ break;
+ if (!dev->ieee80211_ptr->ssid_len)
+ break;
+ cfg80211_leave_ibss(rdev, dev, true);
+ break;
+ case NETDEV_UP:
+#ifdef CONFIG_WIRELESS_EXT
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ break;
+ if (!dev->ieee80211_ptr->wext.ssid_len)
+ break;
+ cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext);
+ break;
+#endif
case NETDEV_UNREGISTER:
mutex_lock(&rdev->devlist_mtx);
if (!list_empty(&dev->ieee80211_ptr->list)) {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 0a592e4295f..3e49d339931 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -10,9 +10,7 @@
#include <linux/netdevice.h>
#include <linux/kref.h>
#include <linux/rbtree.h>
-#include <linux/mutex.h>
#include <net/genetlink.h>
-#include <net/wireless.h>
#include <net/cfg80211.h>
#include "reg.h"
@@ -74,10 +72,7 @@ bool wiphy_idx_valid(int wiphy_idx)
extern struct mutex cfg80211_mutex;
extern struct list_head cfg80211_drv_list;
-static inline void assert_cfg80211_lock(void)
-{
- WARN_ON(!mutex_is_locked(&cfg80211_mutex));
-}
+#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex))
/*
* You can use this to mark a wiphy_idx as not having an associated wiphy.
@@ -148,4 +143,12 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
unsigned long age_secs);
+/* IBSS */
+int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
+int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, bool nowext);
+
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
new file mode 100644
index 00000000000..3c38afaed28
--- /dev/null
+++ b/net/wireless/ibss.c
@@ -0,0 +1,369 @@
+/*
+ * Some IBSS support code for cfg80211.
+ *
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+
+
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+#endif
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return;
+
+ if (WARN_ON(!wdev->ssid_len))
+ return;
+
+ if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
+ return;
+
+ bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+ wdev->ssid, wdev->ssid_len,
+ WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+
+ if (WARN_ON(!bss))
+ return;
+
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(wdev->current_bss);
+ }
+
+ cfg80211_hold_bss(bss);
+ wdev->current_bss = bss;
+ memcpy(wdev->bssid, bssid, ETH_ALEN);
+
+ nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp);
+#ifdef CONFIG_WIRELESS_EXT
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+EXPORT_SYMBOL(cfg80211_ibss_joined);
+
+int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ if (wdev->ssid_len)
+ return -EALREADY;
+
+#ifdef CONFIG_WIRELESS_EXT
+ wdev->wext.channel = params->channel;
+#endif
+ err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
+
+ if (err)
+ return err;
+
+ memcpy(wdev->ssid, params->ssid, params->ssid_len);
+ wdev->ssid_len = params->ssid_len;
+
+ return 0;
+}
+
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(wdev->current_bss);
+ }
+
+ wdev->current_bss = NULL;
+ wdev->ssid_len = 0;
+ memset(wdev->bssid, 0, ETH_ALEN);
+#ifdef CONFIG_WIRELESS_EXT
+ if (!nowext)
+ wdev->wext.ssid_len = 0;
+#endif
+}
+
+int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, bool nowext)
+{
+ int err;
+
+ err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
+
+ if (err)
+ return err;
+
+ cfg80211_clear_ibss(dev, nowext);
+
+ return 0;
+}
+
+#ifdef CONFIG_WIRELESS_EXT
+static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ enum ieee80211_band band;
+ int i;
+
+ if (!wdev->wext.beacon_interval)
+ wdev->wext.beacon_interval = 100;
+
+ /* try to find an IBSS channel if none requested ... */
+ if (!wdev->wext.channel) {
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+
+ sband = rdev->wiphy.bands[band];
+ if (!sband)
+ continue;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+ continue;
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+ wdev->wext.channel = chan;
+ break;
+ }
+
+ if (wdev->wext.channel)
+ break;
+ }
+
+ if (!wdev->wext.channel)
+ return -EINVAL;
+ }
+
+ /* don't join -- SSID is not there */
+ if (!wdev->wext.ssid_len)
+ return 0;
+
+ if (!netif_running(wdev->netdev))
+ return 0;
+
+ return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
+ wdev->netdev, &wdev->wext);
+}
+
+int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct ieee80211_channel *chan;
+ int err;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
+ return -EOPNOTSUPP;
+
+ chan = cfg80211_wext_freq(wdev->wiphy, freq);
+ if (chan && IS_ERR(chan))
+ return PTR_ERR(chan);
+
+ if (chan &&
+ (chan->flags & IEEE80211_CHAN_NO_IBSS ||
+ chan->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+
+ if (wdev->wext.channel == chan)
+ return 0;
+
+ if (wdev->ssid_len) {
+ err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ if (err)
+ return err;
+ }
+
+ if (chan) {
+ wdev->wext.channel = chan;
+ wdev->wext.channel_fixed = true;
+ } else {
+ /* cfg80211_ibss_wext_join will pick one if needed */
+ wdev->wext.channel_fixed = false;
+ }
+
+ return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
+
+int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct ieee80211_channel *chan = NULL;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ if (wdev->current_bss)
+ chan = wdev->current_bss->channel;
+ else if (wdev->wext.channel)
+ chan = wdev->wext.channel;
+
+ if (chan) {
+ freq->m = chan->center_freq;
+ freq->e = 6;
+ return 0;
+ }
+
+ /* no channel if not joining */
+ return -EINVAL;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
+
+int cfg80211_ibss_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ size_t len = data->length;
+ int err;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
+ return -EOPNOTSUPP;
+
+ if (wdev->ssid_len) {
+ err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ if (err)
+ return err;
+ }
+
+ /* iwconfig uses nul termination in SSID.. */
+ if (len > 0 && ssid[len - 1] == '\0')
+ len--;
+
+ wdev->wext.ssid = wdev->ssid;
+ memcpy(wdev->wext.ssid, ssid, len);
+ wdev->wext.ssid_len = len;
+
+ return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
+
+int cfg80211_ibss_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ data->flags = 0;
+
+ if (wdev->ssid_len) {
+ data->flags = 1;
+ data->length = wdev->ssid_len;
+ memcpy(ssid, wdev->ssid, data->length);
+ } else if (wdev->wext.ssid && wdev->wext.ssid_len) {
+ data->flags = 1;
+ data->length = wdev->wext.ssid_len;
+ memcpy(ssid, wdev->wext.ssid, data->length);
+ }
+
+ return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
+
+int cfg80211_ibss_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ u8 *bssid = ap_addr->sa_data;
+ int err;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
+ return -EOPNOTSUPP;
+
+ if (ap_addr->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ /* automatic mode */
+ if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
+ bssid = NULL;
+
+ /* both automatic */
+ if (!bssid && !wdev->wext.bssid)
+ return 0;
+
+ /* fixed already - and no change */
+ if (wdev->wext.bssid && bssid &&
+ compare_ether_addr(bssid, wdev->wext.bssid) == 0)
+ return 0;
+
+ if (wdev->ssid_len) {
+ err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ if (err)
+ return err;
+ }
+
+ if (bssid) {
+ memcpy(wdev->wext_bssid, bssid, ETH_ALEN);
+ wdev->wext.bssid = wdev->wext_bssid;
+ } else
+ wdev->wext.bssid = NULL;
+
+ return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
+
+int cfg80211_ibss_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ /* call only for ibss! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
+ return -EINVAL;
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+
+ if (wdev->wext.bssid) {
+ memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+ return 0;
+ }
+
+ memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
+ return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
+#endif
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index bec5721b6f9..42184361a10 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -28,19 +28,55 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
}
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
-void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len)
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_rx_deauth(rdev, dev, buf, len);
+ nl80211_send_deauth(rdev, dev, buf, len);
}
-EXPORT_SYMBOL(cfg80211_send_rx_deauth);
+EXPORT_SYMBOL(cfg80211_send_deauth);
-void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
- size_t len)
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_rx_disassoc(rdev, dev, buf, len);
+ nl80211_send_disassoc(rdev, dev, buf, len);
}
-EXPORT_SYMBOL(cfg80211_send_rx_disassoc);
+EXPORT_SYMBOL(cfg80211_send_disassoc);
+
+static void cfg80211_wext_disconnected(struct net_device *dev)
+{
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ nl80211_send_auth_timeout(rdev, dev, addr);
+ cfg80211_wext_disconnected(dev);
+}
+EXPORT_SYMBOL(cfg80211_send_auth_timeout);
+
+void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
+{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ nl80211_send_assoc_timeout(rdev, dev, addr);
+ cfg80211_wext_disconnected(dev);
+}
+EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
+
+void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
+ enum nl80211_key_type key_type, int key_id,
+ const u8 *tsc)
+{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc);
+}
+EXPORT_SYMBOL(cfg80211_michael_mic_failure);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2456e4ee445..b1fc98225fd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -61,6 +61,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
+ [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
+ [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -116,8 +120,40 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
.len = IEEE80211_MAX_SSID_LEN },
[NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
+ [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
+ [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
};
+/* IE validation */
+static bool is_valid_ie_attr(const struct nlattr *attr)
+{
+ const u8 *pos;
+ int len;
+
+ if (!attr)
+ return true;
+
+ pos = nla_data(attr);
+ len = nla_len(attr);
+
+ while (len) {
+ u8 elemlen;
+
+ if (len < 2)
+ return false;
+ len -= 2;
+
+ elemlen = pos[1];
+ if (elemlen > len)
+ return false;
+
+ len -= elemlen;
+ pos += 2 + elemlen;
+ }
+
+ return true;
+}
+
/* message building helper */
static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
int flags, u8 cmd)
@@ -126,6 +162,30 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
}
+static int nl80211_msg_put_channel(struct sk_buff *msg,
+ struct ieee80211_channel *chan)
+{
+ 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_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ DBM_TO_MBM(chan->max_power));
+
+ return 0;
+
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
/* netlink command implementations */
static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
@@ -149,8 +209,24 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
+ dev->wiphy.retry_short);
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
+ dev->wiphy.retry_long);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ dev->wiphy.frag_threshold);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+ dev->wiphy.rts_threshold);
+
NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
dev->wiphy.max_scan_ssids);
+ NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+ dev->wiphy.max_scan_ie_len);
+
+ NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
+ sizeof(u32) * dev->wiphy.n_cipher_suites,
+ dev->wiphy.cipher_suites);
nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
if (!nl_modes)
@@ -202,20 +278,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
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_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
- DBM_TO_MBM(chan->max_power));
+ if (nl80211_msg_put_channel(msg, chan))
+ goto nla_put_failure;
nla_nest_end(msg, nl_freq);
}
@@ -273,6 +338,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(assoc, ASSOCIATE);
CMD(deauth, DEAUTHENTICATE);
CMD(disassoc, DISASSOCIATE);
+ CMD(join_ibss, JOIN_IBSS);
#undef CMD
nla_nest_end(msg, nl_cmds);
@@ -365,6 +431,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev;
int result = 0, rem_txq_params = 0;
struct nlattr *nl_txq_params;
+ u32 changed;
+ u8 retry_short = 0, retry_long = 0;
+ u32 frag_threshold = 0, rts_threshold = 0;
rtnl_lock();
@@ -479,6 +548,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
goto bad_res;
}
+ changed = 0;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
+ retry_short = nla_get_u8(
+ info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
+ if (retry_short == 0) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+ changed |= WIPHY_PARAM_RETRY_SHORT;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
+ retry_long = nla_get_u8(
+ info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
+ if (retry_long == 0) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+ changed |= WIPHY_PARAM_RETRY_LONG;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
+ frag_threshold = nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
+ if (frag_threshold < 256) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+ if (frag_threshold != (u32) -1) {
+ /*
+ * Fragments (apart from the last one) are required to
+ * have even length. Make the fragmentation code
+ * simpler by stripping LSB should someone try to use
+ * odd threshold value.
+ */
+ frag_threshold &= ~0x1;
+ }
+ changed |= WIPHY_PARAM_FRAG_THRESHOLD;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) {
+ rts_threshold = nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]);
+ changed |= WIPHY_PARAM_RTS_THRESHOLD;
+ }
+
+ if (changed) {
+ u8 old_retry_short, old_retry_long;
+ u32 old_frag_threshold, old_rts_threshold;
+
+ if (!rdev->ops->set_wiphy_params) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ old_retry_short = rdev->wiphy.retry_short;
+ old_retry_long = rdev->wiphy.retry_long;
+ old_frag_threshold = rdev->wiphy.frag_threshold;
+ old_rts_threshold = rdev->wiphy.rts_threshold;
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT)
+ rdev->wiphy.retry_short = retry_short;
+ if (changed & WIPHY_PARAM_RETRY_LONG)
+ rdev->wiphy.retry_long = retry_long;
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+ rdev->wiphy.frag_threshold = frag_threshold;
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+ rdev->wiphy.rts_threshold = rts_threshold;
+
+ result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
+ if (result) {
+ rdev->wiphy.retry_short = old_retry_short;
+ rdev->wiphy.retry_long = old_retry_long;
+ rdev->wiphy.frag_threshold = old_frag_threshold;
+ rdev->wiphy.rts_threshold = old_rts_threshold;
+ }
+ }
bad_res:
mutex_unlock(&rdev->mtx);
@@ -489,6 +636,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+ struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
void *hdr;
@@ -498,6 +646,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
return -1;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype);
return genlmsg_end(msg, hdr);
@@ -532,7 +681,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
}
if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- wdev->netdev) < 0) {
+ dev, wdev->netdev) < 0) {
mutex_unlock(&dev->devlist_mtx);
goto out;
}
@@ -566,7 +715,8 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
if (!msg)
goto out_err;
- if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
+ if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
+ dev, netdev) < 0)
goto out_free;
dev_put(netdev);
@@ -616,7 +766,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *drv;
struct vif_params params;
int err, ifindex;
- enum nl80211_iftype type;
+ enum nl80211_iftype otype, ntype;
struct net_device *dev;
u32 _flags, *flags = NULL;
bool change = false;
@@ -630,30 +780,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
goto unlock_rtnl;
ifindex = dev->ifindex;
- type = dev->ieee80211_ptr->iftype;
+ otype = ntype = dev->ieee80211_ptr->iftype;
dev_put(dev);
if (info->attrs[NL80211_ATTR_IFTYPE]) {
- enum nl80211_iftype ntype;
-
ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
- if (type != ntype)
+ if (otype != ntype)
change = true;
- type = ntype;
- if (type > NL80211_IFTYPE_MAX) {
+ if (ntype > NL80211_IFTYPE_MAX) {
err = -EINVAL;
goto unlock;
}
}
if (!drv->ops->change_virtual_intf ||
- !(drv->wiphy.interface_modes & (1 << type))) {
+ !(drv->wiphy.interface_modes & (1 << ntype))) {
err = -EOPNOTSUPP;
goto unlock;
}
if (info->attrs[NL80211_ATTR_MESH_ID]) {
- if (type != NL80211_IFTYPE_MESH_POINT) {
+ if (ntype != NL80211_IFTYPE_MESH_POINT) {
err = -EINVAL;
goto unlock;
}
@@ -663,7 +810,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
- if (type != NL80211_IFTYPE_MONITOR) {
+ if (ntype != NL80211_IFTYPE_MONITOR) {
err = -EINVAL;
goto unlock;
}
@@ -678,12 +825,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (change)
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
- type, flags, &params);
+ ntype, flags, &params);
else
err = 0;
dev = __dev_get_by_index(&init_net, ifindex);
- WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
+ WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype));
+
+ if (dev && !err && (ntype != otype)) {
+ if (otype == NL80211_IFTYPE_ADHOC)
+ cfg80211_clear_ibss(dev, false);
+ }
unlock:
cfg80211_put_dev(drv);
@@ -934,7 +1086,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
- int err;
+ int err, i;
struct net_device *dev;
struct key_params params;
u8 key_idx = 0;
@@ -1003,6 +1155,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (err)
goto unlock_rtnl;
+ for (i = 0; i < drv->wiphy.n_cipher_suites; i++)
+ if (params.cipher == drv->wiphy.cipher_suites[i])
+ break;
+ if (i == drv->wiphy.n_cipher_suites) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (!drv->ops->add_key) {
err = -EOPNOTSUPP;
goto out;
@@ -1069,6 +1229,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
struct beacon_parameters params;
int haveinfo = 0;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2442,6 +2605,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
enum ieee80211_band band;
size_t ie_len;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2492,6 +2658,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
else
ie_len = 0;
+ if (ie_len > wiphy->max_scan_ie_len) {
+ err = -EINVAL;
+ goto out;
+ }
+
request = kzalloc(sizeof(*request)
+ sizeof(*ssid) * n_ssids
+ sizeof(channel) * n_channels
@@ -2554,7 +2725,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_IE]) {
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
- memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),
+ memcpy((void *)request->ie,
+ nla_data(info->attrs[NL80211_ATTR_IE]),
request->ie_len);
}
@@ -2710,6 +2882,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
struct wiphy *wiphy;
int err;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2731,11 +2912,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!info->attrs[NL80211_ATTR_MAC]) {
- err = -EINVAL;
- goto out;
- }
-
wiphy = &drv->wiphy;
memset(&req, 0, sizeof(req));
@@ -2761,13 +2937,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
- req.auth_type =
- nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(req.auth_type)) {
- err = -EINVAL;
- goto out;
- }
+ req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(req.auth_type)) {
+ err = -EINVAL;
+ goto out;
}
err = drv->ops->auth(&drv->wiphy, dev, &req);
@@ -2788,6 +2961,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
struct wiphy *wiphy;
int err;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC] ||
+ !info->attrs[NL80211_ATTR_SSID])
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2809,12 +2989,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!info->attrs[NL80211_ATTR_MAC] ||
- !info->attrs[NL80211_ATTR_SSID]) {
- err = -EINVAL;
- goto out;
- }
-
wiphy = &drv->wiphy;
memset(&req, 0, sizeof(req));
@@ -2856,6 +3030,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
struct wiphy *wiphy;
int err;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_REASON_CODE])
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2877,24 +3060,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!info->attrs[NL80211_ATTR_MAC]) {
- err = -EINVAL;
- goto out;
- }
-
wiphy = &drv->wiphy;
memset(&req, 0, sizeof(req));
req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (info->attrs[NL80211_ATTR_REASON_CODE]) {
- req.reason_code =
- nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
- if (req.reason_code == 0) {
- /* Reason Code 0 is reserved */
- err = -EINVAL;
- goto out;
- }
+ req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ if (req.reason_code == 0) {
+ /* Reason Code 0 is reserved */
+ err = -EINVAL;
+ goto out;
}
if (info->attrs[NL80211_ATTR_IE]) {
@@ -2920,6 +3095,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
struct wiphy *wiphy;
int err;
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_REASON_CODE])
+ return -EINVAL;
+
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2941,24 +3125,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!info->attrs[NL80211_ATTR_MAC]) {
- err = -EINVAL;
- goto out;
- }
-
wiphy = &drv->wiphy;
memset(&req, 0, sizeof(req));
req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (info->attrs[NL80211_ATTR_REASON_CODE]) {
- req.reason_code =
- nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
- if (req.reason_code == 0) {
- /* Reason Code 0 is reserved */
- err = -EINVAL;
- goto out;
- }
+ req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ if (req.reason_code == 0) {
+ /* Reason Code 0 is reserved */
+ err = -EINVAL;
+ goto out;
}
if (info->attrs[NL80211_ATTR_IE]) {
@@ -2976,6 +3152,124 @@ unlock_rtnl:
return err;
}
+static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_ibss_params ibss;
+ struct wiphy *wiphy;
+ int err;
+
+ memset(&ibss, 0, sizeof(ibss));
+
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+ !info->attrs[NL80211_ATTR_SSID] ||
+ !nla_len(info->attrs[NL80211_ATTR_SSID]))
+ return -EINVAL;
+
+ ibss.beacon_interval = 100;
+
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ ibss.beacon_interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
+ return -EINVAL;
+ }
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->join_ibss) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ wiphy = &drv->wiphy;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ ibss.channel = ieee80211_get_channel(wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!ibss.channel ||
+ ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
+ ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+
+ err = cfg80211_join_ibss(drv, dev, &ibss);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ int err;
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->leave_ibss) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ err = cfg80211_leave_ibss(drv, dev, false);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -3177,6 +3471,18 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_JOIN_IBSS,
+ .doit = nl80211_join_ibss,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_LEAVE_IBSS,
+ .doit = nl80211_leave_ibss,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",
@@ -3375,22 +3681,197 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
}
-void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf,
- size_t len)
+void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *buf, size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DEAUTHENTICATE);
}
-void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf,
- size_t len)
+void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *buf,
+ size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DISASSOCIATE);
}
+void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, int cmd,
+ const u8 *addr)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
+void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *addr)
+{
+ nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
+ addr);
+}
+
+void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *addr)
+{
+ nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr);
+}
+
+void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
+void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *addr,
+ enum nl80211_key_type key_type, int key_id,
+ const u8 *tsc)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id);
+ if (tsc)
+ NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
+void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
+ struct ieee80211_channel *channel_before,
+ struct ieee80211_channel *channel_after)
+{
+ struct sk_buff *msg;
+ void *hdr;
+ struct nlattr *nl_freq;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ /*
+ * Since we are applying the beacon hint to a wiphy we know its
+ * wiphy_idx is valid
+ */
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy));
+
+ /* Before */
+ nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
+ if (!nl_freq)
+ goto nla_put_failure;
+ if (nl80211_msg_put_channel(msg, channel_before))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_freq);
+
+ /* After */
+ nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
+ if (!nl_freq)
+ goto nla_put_failure;
+ if (nl80211_msg_put_channel(msg, channel_after))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_freq);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+
+ return;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
/* initialisation/exit functions */
int nl80211_init(void)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index b77af4ab80b..5c12ad13499 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -17,11 +17,31 @@ extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len);
-extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len);
-extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len);
+extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len);
+extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len);
+extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *addr);
+extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *addr);
+extern void
+nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *addr,
+ enum nl80211_key_type key_type,
+ int key_id, const u8 *tsc);
+
+extern void
+nl80211_send_beacon_hint_event(struct wiphy *wiphy,
+ struct ieee80211_channel *channel_before,
+ struct ieee80211_channel *channel_after);
+
+void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ gfp_t gfp);
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6c1993d9990..f38cc39fa79 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -37,7 +37,6 @@
#include <linux/random.h>
#include <linux/nl80211.h>
#include <linux/platform_device.h>
-#include <net/wireless.h>
#include <net/cfg80211.h>
#include "core.h"
#include "reg.h"
@@ -1049,18 +1048,10 @@ static void handle_reg_beacon(struct wiphy *wiphy,
unsigned int chan_idx,
struct reg_beacon *reg_beacon)
{
-#ifdef CONFIG_CFG80211_REG_DEBUG
-#define REG_DEBUG_BEACON_FLAG(desc) \
- printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \
- "frequency: %d MHz (Ch %d) on %s\n", \
- reg_beacon->chan.center_freq, \
- ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \
- wiphy_name(wiphy));
-#else
-#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0)
-#endif
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
+ bool channel_changed = false;
+ struct ieee80211_channel chan_before;
assert_cfg80211_lock();
@@ -1070,18 +1061,28 @@ static void handle_reg_beacon(struct wiphy *wiphy,
if (likely(chan->center_freq != reg_beacon->chan.center_freq))
return;
- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+ if (chan->beacon_found)
+ return;
+
+ chan->beacon_found = true;
+
+ chan_before.center_freq = chan->center_freq;
+ chan_before.flags = chan->flags;
+
+ if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+ !(chan->orig_flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
- REG_DEBUG_BEACON_FLAG("active scanning");
+ channel_changed = true;
}
- if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
+ if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
+ !(chan->orig_flags & IEEE80211_CHAN_NO_IBSS)) {
chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
- REG_DEBUG_BEACON_FLAG("beaconing");
+ channel_changed = true;
}
- chan->beacon_found = true;
-#undef REG_DEBUG_BEACON_FLAG
+ if (channel_changed)
+ nl80211_send_beacon_hint_event(wiphy, &chan_before, chan);
}
/*
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 2ae65b39b52..723aeb3d946 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -414,6 +414,55 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
return found;
}
+struct cfg80211_bss*
+cfg80211_inform_bss(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *bssid,
+ u64 timestamp, u16 capability, u16 beacon_interval,
+ const u8 *ie, size_t ielen,
+ s32 signal, gfp_t gfp)
+{
+ struct cfg80211_internal_bss *res;
+ size_t privsz;
+
+ if (WARN_ON(!wiphy))
+ return NULL;
+
+ privsz = wiphy->bss_priv_size;
+
+ if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
+ (signal < 0 || signal > 100)))
+ return NULL;
+
+ res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
+ if (!res)
+ return NULL;
+
+ memcpy(res->pub.bssid, bssid, ETH_ALEN);
+ res->pub.channel = channel;
+ res->pub.signal = signal;
+ res->pub.tsf = timestamp;
+ res->pub.beacon_interval = beacon_interval;
+ res->pub.capability = capability;
+ /* point to after the private area */
+ res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
+ memcpy(res->pub.information_elements, ie, ielen);
+ res->pub.len_information_elements = ielen;
+
+ kref_init(&res->ref);
+
+ res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
+ if (!res)
+ return NULL;
+
+ if (res->pub.capability & WLAN_CAPABILITY_ESS)
+ regulatory_hint_found_beacon(wiphy, channel, gfp);
+
+ /* cfg80211_bss_update gives us a referenced result */
+ return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_inform_bss);
+
struct cfg80211_bss *
cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel,
@@ -604,7 +653,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
cfg80211_put_dev(rdev);
return err;
}
-EXPORT_SYMBOL(cfg80211_wext_siwscan);
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
static void ieee80211_scan_add_ies(struct iw_request_info *info,
struct cfg80211_bss *bss,
@@ -913,5 +962,5 @@ int cfg80211_wext_giwscan(struct net_device *dev,
cfg80211_put_dev(rdev);
return res;
}
-EXPORT_SYMBOL(cfg80211_wext_giwscan);
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
#endif
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 487cdd9bcff..5f7e997195c 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1,10 +1,10 @@
/*
* Wireless utility functions
*
- * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
*/
-#include <net/wireless.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
+#include <net/cfg80211.h>
#include "core.h"
struct ieee80211_rate *
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 0fd1db6e95b..5ef82f2ca88 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -10,8 +10,8 @@
#include <linux/wireless.h>
#include <linux/nl80211.h>
+#include <linux/if_arp.h>
#include <net/iw_handler.h>
-#include <net/wireless.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -57,7 +57,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL(cfg80211_wext_giwname);
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
@@ -108,7 +108,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
return ret;
}
-EXPORT_SYMBOL(cfg80211_wext_siwmode);
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
@@ -143,7 +143,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
}
return 0;
}
-EXPORT_SYMBOL(cfg80211_wext_giwmode);
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
int cfg80211_wext_giwrange(struct net_device *dev,
@@ -206,7 +206,6 @@ int cfg80211_wext_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;
-
for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
int i;
struct ieee80211_supported_band *sband;
@@ -240,4 +239,229 @@ int cfg80211_wext_giwrange(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL(cfg80211_wext_giwrange);
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
+
+int cfg80211_wext_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ struct cfg80211_registered_device *rdev;
+ union {
+ struct cfg80211_disassoc_request disassoc;
+ struct cfg80211_deauth_request deauth;
+ } cmd;
+
+ if (!wdev)
+ return -EOPNOTSUPP;
+
+ rdev = wiphy_to_dev(wdev->wiphy);
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+ if (mlme->addr.sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ if (!rdev->ops->deauth)
+ return -EOPNOTSUPP;
+ cmd.deauth.peer_addr = mlme->addr.sa_data;
+ cmd.deauth.reason_code = mlme->reason_code;
+ return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth);
+ case IW_MLME_DISASSOC:
+ if (!rdev->ops->disassoc)
+ return -EOPNOTSUPP;
+ cmd.disassoc.peer_addr = mlme->addr.sa_data;
+ cmd.disassoc.reason_code = mlme->reason_code;
+ return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
+
+
+/**
+ * cfg80211_wext_freq - get wext frequency for non-"auto"
+ * @wiphy: the wiphy
+ * @freq: the wext freq encoding
+ *
+ * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
+ */
+struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
+ struct iw_freq *freq)
+{
+ if (freq->e == 0) {
+ if (freq->m < 0)
+ return NULL;
+ else
+ return ieee80211_get_channel(wiphy,
+ 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_get_channel(wiphy, freq->m / div);
+ else
+ return ERR_PTR(-EINVAL);
+ }
+
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
+
+int cfg80211_wext_siwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ u32 orts = wdev->wiphy->rts_threshold;
+ int err;
+
+ if (rts->disabled || !rts->fixed)
+ wdev->wiphy->rts_threshold = (u32) -1;
+ else if (rts->value < 0)
+ return -EINVAL;
+ else
+ wdev->wiphy->rts_threshold = rts->value;
+
+ err = rdev->ops->set_wiphy_params(wdev->wiphy,
+ WIPHY_PARAM_RTS_THRESHOLD);
+ if (err)
+ wdev->wiphy->rts_threshold = orts;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
+
+int cfg80211_wext_giwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ rts->value = wdev->wiphy->rts_threshold;
+ rts->disabled = rts->value == (u32) -1;
+ rts->fixed = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
+
+int cfg80211_wext_siwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ u32 ofrag = wdev->wiphy->frag_threshold;
+ int err;
+
+ if (frag->disabled || !frag->fixed)
+ wdev->wiphy->frag_threshold = (u32) -1;
+ else if (frag->value < 256)
+ return -EINVAL;
+ else {
+ /* Fragment length must be even, so strip LSB. */
+ wdev->wiphy->frag_threshold = frag->value & ~0x1;
+ }
+
+ err = rdev->ops->set_wiphy_params(wdev->wiphy,
+ WIPHY_PARAM_FRAG_THRESHOLD);
+ if (err)
+ wdev->wiphy->frag_threshold = ofrag;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
+
+int cfg80211_wext_giwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ frag->value = wdev->wiphy->frag_threshold;
+ frag->disabled = frag->value == (u32) -1;
+ frag->fixed = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
+
+int cfg80211_wext_siwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ u32 changed = 0;
+ u8 olong = wdev->wiphy->retry_long;
+ u8 oshort = wdev->wiphy->retry_short;
+ int err;
+
+ if (retry->disabled ||
+ (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+ return -EINVAL;
+
+ if (retry->flags & IW_RETRY_LONG) {
+ wdev->wiphy->retry_long = retry->value;
+ changed |= WIPHY_PARAM_RETRY_LONG;
+ } else if (retry->flags & IW_RETRY_SHORT) {
+ wdev->wiphy->retry_short = retry->value;
+ changed |= WIPHY_PARAM_RETRY_SHORT;
+ } else {
+ wdev->wiphy->retry_short = retry->value;
+ wdev->wiphy->retry_long = retry->value;
+ changed |= WIPHY_PARAM_RETRY_LONG;
+ changed |= WIPHY_PARAM_RETRY_SHORT;
+ }
+
+ if (!changed)
+ return 0;
+
+ err = rdev->ops->set_wiphy_params(wdev->wiphy, changed);
+ if (err) {
+ wdev->wiphy->retry_short = oshort;
+ wdev->wiphy->retry_long = olong;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry);
+
+int cfg80211_wext_giwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ retry->disabled = 0;
+
+ if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) {
+ /*
+ * First return short value, iwconfig will ask long value
+ * later if needed
+ */
+ retry->flags |= IW_RETRY_LIMIT;
+ retry->value = wdev->wiphy->retry_short;
+ if (wdev->wiphy->retry_long != wdev->wiphy->retry_short)
+ retry->flags |= IW_RETRY_LONG;
+
+ return 0;
+ }
+
+ if (retry->flags & IW_RETRY_LONG) {
+ retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ retry->value = wdev->wiphy->retry_long;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);